code refactory and qos logic

Signed-off-by: fqwert <yanglv2@huawei.com>
Change-Id: I9127a828a3239b38d51ea31ab19020e8cafd6a51
This commit is contained in:
fqwert 2023-11-30 23:11:07 +08:00
parent 5fcb23e203
commit 818959303c
133 changed files with 9029 additions and 5776 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
# Copyright (C) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
target
Cargo.lock

View File

@ -14,5 +14,5 @@
# any change to frameworks/native/include/download_server_ipc_interface_code.h needs to be reviewed by @leonchan5
frameworks/native/include/download_server_ipc_interface_code.h @leonchan5
# any change to services/service/rust/src/download_server_ipc_interface_code.rs needs to be reviewed by @leonchan5
services/service/rust/src/download_server_ipc_interface_code.rs @leonchan5
# any change to services/service/request/src/service/interface.rs needs to be reviewed by @leonchan5
services/service/request/src/service/interface.rs @leonchan5

19
Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
# Copyright (C) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[workspace]
resolver = "2"
members = [
"services/service/request",
"services/service/download_server",
]

View File

@ -67,7 +67,7 @@
"service_group": [
"//base/request/request/services/etc/init:downloadservice.cfg",
"//base/request/request/services/sa_profile:download_sa_profiles",
"//base/request/request/services/service/rust:download_server"
"//base/request/request/services/service/download_server:download_server"
]
},
"inner_kits": [],

View File

@ -101,6 +101,7 @@ struct Config {
uint32_t index = 0;
int64_t begins = 0;
int64_t ends = -1;
uint32_t priority = 0;
bool overwrite = false;
bool metered = false;
bool roaming = false;
@ -209,6 +210,7 @@ struct TaskInfo {
Reason code;
std::string reason;
bool withSystem = false;
uint32_t priority;
std::map<std::string, std::string> extras;
std::vector<TaskState> taskStates;
};

View File

@ -36,7 +36,6 @@ public:
private:
void OnCallBack(MessageParcel &data);
static void OnDone(MessageParcel &data);
bool IsHeaderReceive(const std::string &type, const NotifyData &notifyData);
static void GetDownloadNotify(const std::string &type, const NotifyData &notifyData, Notify &notify);
static void GetUploadNotify(const std::string &type, const NotifyData &notifyData, Notify &notify);

View File

@ -48,10 +48,6 @@ public:
static napi_value Stop(napi_env env, napi_callback_info info);
static std::map<Reason, DownloadErrorCode> failMap_;
static void AddCache(const std::string &taskId, const std::shared_ptr<TaskInfo> &info);
static bool GetCache(const std::string &taskId, std::shared_ptr<TaskInfo> &info);
static void RemoveCache(const std::string &taskId);
private:
struct JsParam {
std::string type;
@ -93,10 +89,6 @@ private:
static NotifyData BuildNotifyData(const std::shared_ptr<TaskInfo> &taskInfo);
static bool IsSupportType(const std::string &type, Version version);
static void ConvertType(std::string &type);
static bool NeedNotify(const std::string &type, std::shared_ptr<TaskInfo> &taskInfo);
static std::mutex taskCacheMutex_;
static std::map<std::string, std::shared_ptr<TaskInfo>> taskCache_;
};
} // namespace OHOS::Request

View File

@ -76,7 +76,6 @@ JsTask::~JsTask()
{
REQUEST_HILOGD("~JsTask()");
ClearListener();
RequestEvent::RemoveCache(tid_);
}
napi_value JsTask::JsUpload(napi_env env, napi_callback_info info)
{

View File

@ -370,6 +370,7 @@ napi_value Convert2JSValue(napi_env env, TaskInfo &taskInfo)
napi_set_named_property(env, value, "mimeType", Convert2JSValue(env, taskInfo.mimeType));
napi_set_named_property(env, value, "progress", Convert2JSValue(env, taskInfo.progress));
napi_set_named_property(env, value, "gauge", Convert2JSValue(env, taskInfo.gauge));
napi_set_named_property(env, value, "priority", Convert2JSValue(env, taskInfo.priority));
napi_set_named_property(env, value, "ctime", Convert2JSValue(env, taskInfo.ctime));
napi_set_named_property(env, value, "mtime", Convert2JSValue(env, taskInfo.mtime));
napi_set_named_property(env, value, "retry", Convert2JSValue(env, taskInfo.retry));

View File

@ -33,7 +33,6 @@ int32_t NotifyStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageP
OnCallBack(data);
break;
case static_cast<uint32_t>(RequestNotifyInterfaceCode::REQUEST_DONE_NOTIFY):
OnDone(data);
break;
default:
REQUEST_HILOGE("Default value received, check needed.");
@ -78,7 +77,8 @@ void NotifyStub::OnCallBack(MessageParcel &data)
notifyData.taskStates.push_back(taskState);
}
RequestCallBack(type, tid, notifyData);
if (notifyData.version == Version::API10 && (type == "complete" || type == "fail")) {
if (type == "complete" || type == "fail") {
JsTask::ClearTaskContext(tid);
}
}
@ -187,19 +187,4 @@ void NotifyStub::GetUploadNotify(const std::string &type, const NotifyData &noti
notify.progress.extras = notifyData.progress.extras;
}
}
void NotifyStub::OnDone(MessageParcel &data)
{
auto taskInfo = std::make_shared<TaskInfo>();
ParcelHelper::UnMarshal(data, *taskInfo);
REQUEST_HILOGI("task %{public}s done", taskInfo->tid.c_str());
std::lock_guard<std::mutex> lockGuard(JsTask::taskMutex_);
auto item = JsTask::taskMap_.find(taskInfo->tid);
if (item == JsTask::taskMap_.end()) {
REQUEST_HILOGW("Task ID not found");
return;
}
RequestEvent::AddCache(taskInfo->tid, taskInfo);
JsTask::ClearTaskContext(taskInfo->tid);
}
} // namespace OHOS::Request

View File

@ -89,8 +89,6 @@ std::map<Reason, DownloadErrorCode> RequestEvent::failMap_ = {
{UNSUPPORT_RANGE_REQUEST, ERROR_UNKNOWN},
};
std::mutex RequestEvent::taskCacheMutex_;
std::map<std::string, std::shared_ptr<TaskInfo>> RequestEvent::taskCache_;
napi_value RequestEvent::Pause(napi_env env, napi_callback_info info)
{
REQUEST_HILOGD("Pause in");
@ -151,38 +149,12 @@ napi_value RequestEvent::On(napi_env env, napi_callback_info info)
REQUEST_HILOGD("On event %{public}s + %{public}s", jsParam.type.c_str(), jsParam.task->GetTid().c_str());
std::string key = jsParam.type + jsParam.task->GetTid();
jsParam.task->AddListener(key, listener);
std::shared_ptr<TaskInfo> taskInfo;
if (GetCache(jsParam.task->GetTid(), taskInfo) && taskInfo != nullptr) {
if (!NeedNotify(jsParam.type, taskInfo)) {
return nullptr;
}
listener->RequestCallBack(jsParam.type, jsParam.task->GetTid(), BuildNotifyData(taskInfo));
return nullptr;
}
if (jsParam.task->GetListenerSize(key) == 1) {
RequestManager::GetInstance()->On(jsParam.type, jsParam.task->GetTid(), listener);
}
return nullptr;
}
bool RequestEvent::NeedNotify(const std::string &type, std::shared_ptr<TaskInfo> &taskInfo)
{
if (type == EVENT_FAIL && taskInfo->progress.state != State::FAILED) {
return false;
}
if (type == EVENT_COMPLETE && taskInfo->progress.state != State::COMPLETED) {
return false;
}
if (!taskInfo->progress.sizes.empty()) {
uint64_t processed = taskInfo->progress.processed;
int64_t totalSize = taskInfo->progress.sizes[0];
if (type == EVENT_PROGRESS && processed == 0 && totalSize == -1) {
return false;
}
}
return true;
}
napi_value RequestEvent::Off(napi_env env, napi_callback_info info)
{
JsParam jsParam;
@ -353,16 +325,17 @@ int32_t RequestEvent::PauseExec(const std::shared_ptr<ExecContext> &context)
int32_t RequestEvent::QueryExec(const std::shared_ptr<ExecContext> &context)
{
std::shared_ptr<TaskInfo> infoRes;
TaskInfo infoRes;
int32_t ret = E_OK;
if (!GetCache(context->task->GetTid(), infoRes) || infoRes == nullptr) {
infoRes = std::make_shared<TaskInfo>();
ret = RequestManager::GetInstance()->Show(context->task->GetTid(), *infoRes);
if (!RequestManager::GetInstance()->LoadRequestServer()) {
ret = E_SERVICE_ERROR;
return ret;
}
ret = RequestManager::GetInstance()->Show(context->task->GetTid(), infoRes);
if (context->version_ != Version::API10 && ret != E_PERMISSION) {
ret = E_OK;
}
GetDownloadInfo(*infoRes, context->infoRes);
GetDownloadInfo(infoRes, context->infoRes);
return ret;
}
@ -370,8 +343,8 @@ int32_t RequestEvent::QueryMimeTypeExec(const std::shared_ptr<ExecContext> &cont
{
std::shared_ptr<TaskInfo> infoRes;
int32_t ret = E_OK;
if (GetCache(context->task->GetTid(), infoRes) || infoRes != nullptr) {
context->strRes = infoRes->mimeType;
if (!RequestManager::GetInstance()->LoadRequestServer()) {
ret = E_SERVICE_ERROR;
return ret;
}
ret = RequestManager::GetInstance()->QueryMimeType(context->task->GetTid(), context->strRes);
@ -441,30 +414,4 @@ int32_t RequestEvent::ResumeExec(const std::shared_ptr<ExecContext> &context)
}
return ret;
}
void RequestEvent::AddCache(const std::string &taskId, const std::shared_ptr<TaskInfo> &info)
{
REQUEST_HILOGI("AddCache in, task id is %{public}s", taskId.c_str());
std::lock_guard<std::mutex> lock(taskCacheMutex_);
taskCache_[taskId] = info;
}
bool RequestEvent::GetCache(const std::string &taskId, std::shared_ptr<TaskInfo> &info)
{
REQUEST_HILOGI("GetCache in, task id is %{public}s", taskId.c_str());
std::lock_guard<std::mutex> lock(taskCacheMutex_);
auto it = taskCache_.find(taskId);
if (it != taskCache_.end()) {
info = it->second;
return true;
}
return false;
}
void RequestEvent::RemoveCache(const std::string &taskId)
{
std::lock_guard<std::mutex> lock(taskCacheMutex_);
REQUEST_HILOGI("RemoveCache in, task id is %{public}s", taskId.c_str());
taskCache_.erase(taskId);
}
} // namespace OHOS::Request

View File

@ -59,6 +59,7 @@ void ParcelHelper::UnMarshalBase(MessageParcel &data, TaskInfo &info)
info.mtime = data.ReadUint64();
info.data = data.ReadString();
info.description = data.ReadString();
info.priority = data.ReadUint32();
}
bool ParcelHelper::UnMarshalFormItem(MessageParcel &data, TaskInfo &info)

View File

@ -54,6 +54,7 @@ int32_t RequestServiceProxy::Create(const Config &config, int32_t &tid, sptr<Not
data.WriteInt64(config.ends);
data.WriteBool(config.gauge);
data.WriteBool(config.precise);
data.WriteUint32(config.priority);
data.WriteString(config.url);
data.WriteString(config.title);
data.WriteString(config.method);
@ -283,7 +284,13 @@ int32_t RequestServiceProxy::Remove(const std::string &tid, Version version)
REQUEST_HILOGE("send request ret code is %{public}d", ret);
return E_SERVICE_ERROR;
}
return reply.ReadInt32();
// API9 or lower will not return E_TASK_NOT_FOUND.
int32_t result = reply.ReadInt32();
if (version == Version::API9) {
result = E_OK;
}
return result;
}
int32_t RequestServiceProxy::Resume(const std::string &tid)

19
rustfmt.toml Normal file
View File

@ -0,0 +1,19 @@
# Copyright (C) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
edition = "2021"
wrap_comments = true
imports_granularity = "Module"
group_imports = "StdExternalCrate"
format_code_in_doc_comments = true
normalize_comments = true

View File

@ -0,0 +1,51 @@
# Copyright (C) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//base/request/request/request_aafwk.gni")
import("//build/ohos.gni")
config("download_service_config") {
visibility = [ ":*" ]
include_dirs = [ "include" ]
ldflags = [ "-Wl,--exclude-libs=ALL" ]
cflags_cc = [ "-fno-exceptions" ]
cflags = [
"-fdata-sections",
"-ffunction-sections",
"-fvisibility=hidden",
]
}
ohos_rust_shared_library("download_server") {
sources = [ "src/lib.rs" ]
public_configs = [ ":download_service_config" ]
deps = [ "../request:request" ]
external_deps = [
"hilog:hilog_rust",
"hisysevent:hisysevent_rust",
"ipc:ipc_rust",
"safwk:system_ability_fwk_rust",
]
rustflags = [
"-Copt-level=3",
"-Cprefer-dynamic",
]
crate_name = "download_server"
subsystem_name = "request"
part_name = "request"
}

View File

@ -0,0 +1,25 @@
# Copyright (C) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[package]
name = "download_server"
version = "1.0.0"
edition = "2021"
license = "Apache-2.0"
[dependencies]
request = { path = "../request", features = ["oh"] }
hilog_rust = { git = "https://gitee.com/openharmony/hiviewdfx_hilog.git" }
ipc_rust = { git = "https://gitee.com/openharmony/communication_ipc" }
hisysevent = { git = "https://gitee.com/openharmony/hiviewdfx_hisysevent.git" }
system_ability_fwk_rust = { git = "https://gitee.com/openharmony/systemabilitymgr_safwk" }

View File

@ -1,36 +1,31 @@
/*
* Copyright (C) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This create implement the request server register and publish
#![allow(unused_variables)]
extern crate ipc_rust;
extern crate request;
extern crate system_ability_fwk_rust;
extern crate hisysevent;
use hilog_rust::*;
use hisysevent::{EventType, write, build_number_param};
#![warn(missing_docs, unused_crate_dependencies)]
use std::ffi::{c_char, CString};
use hilog_rust::{error, hilog, info};
use hisysevent::{build_number_param, write, EventType};
use ipc_rust::{IRemoteBroker, RemoteObj};
pub use request::{start, stop, RequestService, RequestServiceStub, LOG_LABEL};
use std::ffi::{c_char, CString};
use system_ability_fwk_rust::{define_system_ability, IMethod, ISystemAbility, RSystemAbility};
/// TEST_SERVICE_ID SAID
pub const REQUEST_SERVICE_ID: i32 = 3706;
fn on_start<T: ISystemAbility + IMethod>(ability: &T) {
debug!(LOG_LABEL, "on_start");
info!(LOG_LABEL, "on_start");
let service = match RequestServiceStub::new_remote_stub(RequestService) {
Some(service) => service,
None => {
@ -49,11 +44,13 @@ fn on_start<T: ISystemAbility + IMethod>(ability: &T) {
ability.publish(&object, REQUEST_SERVICE_ID);
start();
info!(LOG_LABEL, "on_start succeed");
}
fn on_stop<T: ISystemAbility + IMethod>(ability: &T) {
debug!(LOG_LABEL, "on_stop");
fn on_stop<T: ISystemAbility + IMethod>(_ability: &T) {
info!(LOG_LABEL, "on_stop");
stop();
info!(LOG_LABEL, "on_stop succeed");
}
fn service_start_fault() {
@ -66,7 +63,7 @@ fn service_start_fault() {
DOMAIN,
SERVICE_START_FAULT,
EventType::Fault,
&[build_number_param!(ERROR_INFO, DOWNLOAD_PUBLISH_FAIL)]
&[build_number_param!(ERROR_INFO, DOWNLOAD_PUBLISH_FAIL)],
);
}
@ -76,7 +73,7 @@ define_system_ability!(sa: SystemAbility(on_start, on_stop),);
#[link_section = ".init_array"]
static A: extern "C" fn() = {
extern "C" fn init() {
debug!(LOG_LABEL, "request service init");
info!(LOG_LABEL, "request service init");
let system_ability = SystemAbility::new_system_ability(REQUEST_SERVICE_ID, false)
.expect("create service failed");
system_ability.register();

View File

@ -27,74 +27,26 @@ config("download_service_config") {
]
}
ohos_rust_shared_library("download_server") {
sources = [ "src/request_service_init.rs" ]
public_configs = [ ":download_service_config" ]
deps = [ ":request" ]
external_deps = [
"hilog:hilog_rust",
"hisysevent:hisysevent_rust",
"ipc:ipc_rust",
"safwk:system_ability_fwk_rust",
]
clippy_lints = "none"
rustflags = [
"-Copt-level=3",
"-Cprefer-dynamic",
]
crate_name = "download_server"
crate_type = "dylib"
subsystem_name = "request"
part_name = "request"
}
ohos_rust_shared_library("request") {
sources = [
"src/c_string_wrapper.rs",
"src/download_server_ipc_interface_code.rs",
"src/enumration.rs",
"src/filter.rs",
"src/form_item.rs",
"src/lib.rs",
"src/log.rs",
"src/progress.rs",
"src/request_binding.rs",
"src/request_service.rs",
"src/request_service_ability.rs",
"src/request_task.rs",
"src/task_config.rs",
"src/task_info.rs",
"src/task_manager.rs",
"src/utils.rs",
]
sources = [ "src/lib.rs" ]
public_configs = [ ":download_service_config" ]
deps = [ ":request_service_c" ]
features = [ "oh" ]
external_deps = [
"hilog:hilog_rust",
"hisysevent:hisysevent_rust",
"hitrace:hitrace_meter_rust",
"ipc:ipc_rust",
"netstack:ylong_http_client",
"safwk:system_ability_fwk_rust",
"samgr:rust_samgr",
"ylong_runtime:ylong_runtime",
]
clippy_lints = "none"
rustflags = [
"-Copt-level=3",
"-Cprefer-dynamic",
"-Zmacro-backtrace",
]
crate_name = "request"
crate_type = "dylib"
subsystem_name = "request"
part_name = "request"
}
@ -102,24 +54,24 @@ ohos_rust_shared_library("request") {
ohos_shared_library("request_service_c") {
include_dirs = [
"${request_path}/common/include",
"${request_path}/services/service/rust/src/c_wrapper/include",
"${request_path}/services/service/request/c_wrapper/include",
"${core_service_path}/innerkits/include",
"${cellular_data_path}/innerkits/include",
"${notification_path}/interfaces/inner_api",
]
sources = [
"${request_path}/services/service/rust/src/c_wrapper/source/application_state_observer.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/background_notification.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/c_check_permission.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/c_event_handler.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/c_request_database.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/c_string_wrapper.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/c_task_config.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/c_task_info.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/common_event_notify.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/get_calling_bundle.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/get_top_bundle.cpp",
"${request_path}/services/service/rust/src/c_wrapper/source/network_adapter.cpp",
"${request_path}/services/service/request/c_wrapper/source/application_state_observer.cpp",
"${request_path}/services/service/request/c_wrapper/source/background_notification.cpp",
"${request_path}/services/service/request/c_wrapper/source/c_check_permission.cpp",
"${request_path}/services/service/request/c_wrapper/source/c_event_handler.cpp",
"${request_path}/services/service/request/c_wrapper/source/c_request_database.cpp",
"${request_path}/services/service/request/c_wrapper/source/c_string_wrapper.cpp",
"${request_path}/services/service/request/c_wrapper/source/c_task_config.cpp",
"${request_path}/services/service/request/c_wrapper/source/c_task_info.cpp",
"${request_path}/services/service/request/c_wrapper/source/common_event_notify.cpp",
"${request_path}/services/service/request/c_wrapper/source/get_calling_bundle.cpp",
"${request_path}/services/service/request/c_wrapper/source/get_top_bundle.cpp",
"${request_path}/services/service/request/c_wrapper/source/network_adapter.cpp",
]
cflags_cc = [ "-O2" ]

View File

@ -0,0 +1,42 @@
# Copyright (C) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[package]
name = "request"
version = "1.0.0"
edition = "2021"
license = "Apache-2.0"
[features]
default = []
oh = ["hilog_rust", "hisysevent", "hitrace_meter_rust", "rust_samgr", "ipc_rust"]
[dependencies]
ylong_runtime = { git = "https://gitee.com/openharmony/commonlibrary_rust_ylong_runtime", features = ["full"] }
ylong_http_client = { git = "https://gitee.com/openharmony/commonlibrary_rust_ylong_http", features = [
"async",
"c_openssl_3_0",
"http1_1",
"ylong_base",
] }
hilog_rust = { git = "https://gitee.com/openharmony/hiviewdfx_hilog.git", optional = true }
hisysevent = { git = "https://gitee.com/openharmony/hiviewdfx_hisysevent.git", optional = true }
hitrace_meter_rust = { git = "https://gitee.com/openharmony/hiviewdfx_hitrace.git", optional = true }
rust_samgr = { git = "https://gitee.com/openharmony/systemabilitymgr_samgr.git", optional = true }
ipc_rust = { git = "https://gitee.com/openharmony/communication_ipc.git", optional = true }
log = { version = "0.4.20" }
env_logger = { version = "0.10.1" }

View File

@ -66,7 +66,8 @@ constexpr const char *CREATE_REQUEST_TABLE1 = "CREATE TABLE IF NOT EXISTS reques
"processed TEXT, "
"extras TEXT, "
"form_items_len INTEGER, "
"file_specs_len INTEGER)";
"file_specs_len INTEGER, "
"priority INTEGER)";
constexpr const char *CREATE_REQUEST_TABLE2 = "CREATE TABLE IF NOT EXISTS task_info_attachment "
"(id INTEGER PRIMARY KEY AUTOINCREMENT, "
@ -111,7 +112,8 @@ constexpr const char *CREATE_REQUEST_TABLE3 = "CREATE TABLE IF NOT EXISTS reques
"version INTEGER, "
"form_items_len INTEGER, "
"file_specs_len INTEGER, "
"body_file_names_len INTEGER)";
"body_file_names_len INTEGER, "
"priority INTEGER)";
constexpr const char *CREATE_REQUEST_TABLE4 = "CREATE TABLE IF NOT EXISTS task_config_attachment "
"(id INTEGER PRIMARY KEY AUTOINCREMENT, "
@ -166,6 +168,7 @@ struct CVectorWrapper {
bool HasRequestTaskRecord(uint32_t taskId);
bool RecordRequestTaskInfo(CTaskInfo *taskInfo);
bool UpdateRequestTaskInfo(uint32_t taskId, CUpdateInfo *updateInfo);
CTaskInfo *Show(uint32_t taskId, uint64_t uid);
CTaskInfo *Touch(uint32_t taskId, uint64_t uid, CStringWrapper token);
CTaskInfo *Query(uint32_t taskId, Action queryAction);
CVectorWrapper Search(CFilter filter);
@ -186,6 +189,7 @@ bool RecordRequestTaskConfig(CTaskConfig *taskConfig);
void GetCommonTaskConfig(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, TaskConfig &taskConfig);
CTaskConfig **QueryAllTaskConfig();
int QueryTaskConfigLen();
void QuerySingleTaskConfig(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, TaskConfig &taskConfig);
int QueryRequestTaskConfig(const OHOS::NativeRdb::RdbPredicates &rdbPredicates, std::vector<TaskConfig> &taskConfigs);
int QueryTaskConfigAttachment(const OHOS::NativeRdb::RdbPredicates &rdbPredicates, TaskConfig &taskConfig,
int64_t formItemsLen, int64_t fileSpecsLen, int64_t bodyFileNamesLen);

View File

@ -41,6 +41,7 @@ struct CommonTaskConfig {
int64_t ends;
bool gauge;
bool precise;
uint32_t priority;
bool background;
};

View File

@ -37,6 +37,7 @@ struct CommonTaskInfo {
bool retry;
uint32_t tries;
uint8_t version;
uint32_t priority;
};
struct CEachFileStatus {

View File

@ -197,6 +197,7 @@ bool WriteRequestTaskInfo(CTaskInfo *taskInfo)
insertValues.PutInt("retry", taskInfo->commonData.retry);
insertValues.PutLong("tries", taskInfo->commonData.tries);
insertValues.PutInt("version", taskInfo->commonData.version);
insertValues.PutLong("priority", taskInfo->commonData.priority);
insertValues.PutString("bundle", std::string(taskInfo->bundle.cStr, taskInfo->bundle.len));
insertValues.PutString("url", std::string(taskInfo->url.cStr, taskInfo->url.len));
insertValues.PutString("data", std::string(taskInfo->data.cStr, taskInfo->data.len));
@ -301,6 +302,26 @@ bool UpdateRequestTaskInfo(uint32_t taskId, CUpdateInfo *updateInfo)
return true;
}
CTaskInfo *Show(uint32_t taskId, uint64_t uid)
{
OHOS::NativeRdb::RdbPredicates rdbPredicates1("request_task_info");
rdbPredicates1.EqualTo("task_id", std::to_string(taskId))
->And()
->EqualTo("uid", std::to_string(uid));
int64_t formItemsLen = 0;
int64_t fileSpecsLen = 0;
TaskInfo taskInfo;
if (TouchRequestTaskInfo(rdbPredicates1, taskInfo, formItemsLen, fileSpecsLen) == OHOS::Request::QUERY_ERR) {
return nullptr;
}
OHOS::NativeRdb::RdbPredicates rdbPredicates2("task_info_attachment");
rdbPredicates2.EqualTo("task_id", std::to_string(taskId))->And()->EqualTo("uid", std::to_string(uid));
if (TouchTaskInfoAttachment(rdbPredicates2, taskInfo, formItemsLen, fileSpecsLen) == OHOS::Request::QUERY_ERR) {
return nullptr;
}
return BuildCTaskInfo(taskInfo);
}
CTaskInfo *Touch(uint32_t taskId, uint64_t uid, CStringWrapper token)
{
OHOS::NativeRdb::RdbPredicates rdbPredicates1("request_task_info");
@ -405,27 +426,27 @@ void GetCommonTaskInfo(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, Ta
int64_t tries = 0;
int version = 0;
resultSet->GetLong(0, taskId);
resultSet->GetLong(0, taskId); // Line 0 here is 'task_id'
taskInfo.commonData.taskId = static_cast<uint32_t>(taskId);
resultSet->GetLong(1, uid);
resultSet->GetLong(1, uid); // Line 1 here is 'uid'
taskInfo.commonData.uid = static_cast<uint64_t>(uid);
resultSet->GetInt(2, action);
resultSet->GetInt(2, action); // Line 2 here is 'action'
taskInfo.commonData.action = static_cast<uint8_t>(action);
resultSet->GetInt(3, mode);
resultSet->GetInt(3, mode); // Line 3 here is 'mode'
taskInfo.commonData.mode = static_cast<uint8_t>(mode);
resultSet->GetLong(4, ctime);
resultSet->GetLong(4, ctime); // Line 4 here is 'ctime'
taskInfo.commonData.ctime = static_cast<uint64_t>(ctime);
resultSet->GetLong(5, mtime);
resultSet->GetLong(5, mtime); // Line 5 here is 'mtime'
taskInfo.commonData.mtime = static_cast<uint64_t>(mtime);
resultSet->GetInt(6, reason);
resultSet->GetInt(6, reason); // Line 6 here is 'reason'
taskInfo.commonData.reason = static_cast<uint8_t>(reason);
resultSet->GetInt(7, gauge);
resultSet->GetInt(7, gauge); // Line 7 here is 'gauge'
taskInfo.commonData.gauge = static_cast<bool>(gauge);
resultSet->GetInt(8, retry);
resultSet->GetInt(8, retry); // Line 8 here is 'retry'
taskInfo.commonData.retry = static_cast<bool>(retry);
resultSet->GetLong(9, tries);
resultSet->GetLong(9, tries); // Line 9 here is 'tries'
taskInfo.commonData.tries = static_cast<uint32_t>(tries);
resultSet->GetInt(10, version);
resultSet->GetInt(10, version); // Line 10 here is 'version'
taskInfo.commonData.version = static_cast<uint8_t>(version);
}
@ -435,7 +456,7 @@ int TouchRequestTaskInfo(const OHOS::NativeRdb::RdbPredicates &rdbPredicates, Ta
auto resultSet = OHOS::Request::RequestDataBase::GetInstance().Query(rdbPredicates,
{ "task_id", "uid", "action", "mode", "ctime", "mtime", "reason", "gauge", "retry", "tries", "version", "url",
"data", "titile", "description", "mime_type", "state", "idx", "total_processed", "sizes", "processed",
"extras", "form_items_len", "file_specs_len" });
"extras", "form_items_len", "file_specs_len", "priority" });
if (resultSet == nullptr || resultSet->GoToFirstRow() != OHOS::NativeRdb::E_OK) {
REQUEST_HILOGE("result set is nullptr or go to first row failed");
return OHOS::Request::QUERY_ERR;
@ -443,23 +464,26 @@ int TouchRequestTaskInfo(const OHOS::NativeRdb::RdbPredicates &rdbPredicates, Ta
int state = 0;
int64_t idx = 0;
int64_t totalProcessed = 0;
int64_t priority = 0;
GetCommonTaskInfo(resultSet, taskInfo);
resultSet->GetString(11, taskInfo.url);
resultSet->GetString(12, taskInfo.data);
resultSet->GetString(13, taskInfo.title);
resultSet->GetString(14, taskInfo.description);
resultSet->GetString(15, taskInfo.mimeType);
resultSet->GetInt(16, state);
resultSet->GetString(11, taskInfo.url); // Line 11 here is 'url'
resultSet->GetString(12, taskInfo.data); // Line 12 here is 'data'
resultSet->GetString(13, taskInfo.title); // Line 13 here is 'title'
resultSet->GetString(14, taskInfo.description); // Line 14 here is 'description'
resultSet->GetString(15, taskInfo.mimeType); // Line 15 here is 'mimeType'
resultSet->GetInt(16, state); // Line 16 here is 'state'
taskInfo.progress.commonData.state = static_cast<uint8_t>(state);
resultSet->GetLong(17, idx);
resultSet->GetLong(17, idx); // Line 17 here is 'idx'
taskInfo.progress.commonData.index = static_cast<uintptr_t>(idx);
resultSet->GetLong(18, totalProcessed);
resultSet->GetLong(18, totalProcessed); // Line 18 here is 'totalProcessed'
taskInfo.progress.commonData.totalProcessed = static_cast<uintptr_t>(totalProcessed);
resultSet->GetString(19, taskInfo.progress.sizes);
resultSet->GetString(20, taskInfo.progress.processed);
resultSet->GetString(21, taskInfo.progress.extras);
resultSet->GetLong(22, formItemsLen);
resultSet->GetLong(23, fileSpecsLen);
resultSet->GetString(19, taskInfo.progress.sizes); // Line 19 here is 'sizes'
resultSet->GetString(20, taskInfo.progress.processed); // Line 20 here is 'processed'
resultSet->GetString(21, taskInfo.progress.extras); // Line 21 here is 'extras'
resultSet->GetLong(22, formItemsLen); // Line 22 here is 'formItemsLen'
resultSet->GetLong(23, fileSpecsLen); // Line 23 here is 'fileSpecsLen'
resultSet->GetLong(24, priority); // Line 24 here is 'priority'
taskInfo.commonData.priority = static_cast<uint32_t>(priority);
resultSet->Close();
return OHOS::Request::QUERY_OK;
}
@ -478,22 +502,25 @@ int QueryRequestTaskInfo(const OHOS::NativeRdb::RdbPredicates &rdbPredicates, Ta
int state = 0;
int64_t idx = 0;
int64_t totalProcessed = 0;
int64_t priority = 0;
GetCommonTaskInfo(resultSet, taskInfo);
resultSet->GetString(11, taskInfo.bundle);
resultSet->GetString(12, taskInfo.title);
resultSet->GetString(13, taskInfo.description);
resultSet->GetString(14, taskInfo.mimeType);
resultSet->GetInt(15, state);
resultSet->GetString(11, taskInfo.bundle); // Line 11 here is 'bundle'
resultSet->GetString(12, taskInfo.title); // Line 12 here is 'title'
resultSet->GetString(13, taskInfo.description); // Line 13 here is 'description'
resultSet->GetString(14, taskInfo.mimeType); // Line 14 here is 'mimeType'
resultSet->GetInt(15, state); // Line 15 here is 'state'
taskInfo.progress.commonData.state = static_cast<uint8_t>(state);
resultSet->GetLong(16, idx);
resultSet->GetLong(16, idx); // Line 16 here is 'idx'
taskInfo.progress.commonData.index = static_cast<uintptr_t>(idx);
resultSet->GetLong(17, totalProcessed);
resultSet->GetLong(17, totalProcessed); // Line 17 here is 'totalProcessed'
taskInfo.progress.commonData.totalProcessed = static_cast<uintptr_t>(totalProcessed);
resultSet->GetString(18, taskInfo.progress.sizes);
resultSet->GetString(19, taskInfo.progress.processed);
resultSet->GetString(20, taskInfo.progress.extras);
resultSet->GetLong(21, formItemsLen);
resultSet->GetLong(22, fileSpecsLen);
resultSet->GetString(18, taskInfo.progress.sizes); // Line 18 here is 'sizes'
resultSet->GetString(19, taskInfo.progress.processed); // Line 19 here is 'processed'
resultSet->GetString(20, taskInfo.progress.extras); // Line 20 here is 'extras'
resultSet->GetLong(21, formItemsLen); // Line 21 here is 'formItemsLen'
resultSet->GetLong(22, fileSpecsLen); // Line 22 here is 'fileSpecsLen'
resultSet->GetLong(23, priority); // Line 23 here is 'priority'
taskInfo.commonData.priority = static_cast<uint32_t>(priority);
resultSet->Close();
return OHOS::Request::QUERY_OK;
}
@ -515,25 +542,25 @@ int TouchTaskInfoAttachment(const OHOS::NativeRdb::RdbPredicates &rdbPredicates,
}
if (i < formItemsLen) {
FormItem formItem;
resultSet->GetString(0, formItem.name);
resultSet->GetString(1, formItem.value);
resultSet->GetString(0, formItem.name); // Line 0 here is 'name'
resultSet->GetString(1, formItem.value); // Line 1 here is 'value'
taskInfo.formItems.push_back(std::move(formItem));
}
if (i < fileSpecsLen) {
FileSpec fileSpec;
std::string path;
resultSet->GetString(2, fileSpec.name);
resultSet->GetString(3, path);
resultSet->GetString(4, fileSpec.fileName);
resultSet->GetString(5, fileSpec.mimeType);
resultSet->GetString(2, fileSpec.name); // Line 2 here is 'name'
resultSet->GetString(3, path); // Line 3 here is 'path'
resultSet->GetString(4, fileSpec.fileName); // Line 4 here is 'fileName'
resultSet->GetString(5, fileSpec.mimeType); // Line 5 here is 'mimeType'
fileSpec.path = path;
taskInfo.fileSpecs.push_back(std::move(fileSpec));
EachFileStatus eachFileStatus;
eachFileStatus.path = std::move(path);
int reason = 0;
resultSet->GetInt(6, reason);
resultSet->GetInt(6, reason); // Line 6 here is 'reason'
eachFileStatus.reason = static_cast<uint8_t>(reason);
resultSet->GetString(7, eachFileStatus.message);
resultSet->GetString(7, eachFileStatus.message); // Line 7 here is 'message'
taskInfo.eachFileStatus.push_back(std::move(eachFileStatus));
}
}
@ -560,9 +587,9 @@ int QueryTaskInfoAttachment(const OHOS::NativeRdb::RdbPredicates &rdbPredicates,
resultSet->GetString(0, path);
eachFileStatus.path = path;
int reason = 0;
resultSet->GetInt(1, reason);
resultSet->GetInt(1, reason); // Line 1 here is 'reason'
eachFileStatus.reason = static_cast<uint8_t>(reason);
resultSet->GetString(2, eachFileStatus.message);
resultSet->GetString(2, eachFileStatus.message); // Line 2 here is 'message'
taskInfo.eachFileStatus.push_back(std::move(eachFileStatus));
FileSpec fileSpec;
fileSpec.path = std::move(path);
@ -663,6 +690,7 @@ bool WriteRequestTaskConfig(CTaskConfig *taskConfig)
insertValues.PutLong("ends", taskConfig->commonData.ends);
insertValues.PutInt("gauge", taskConfig->commonData.gauge);
insertValues.PutInt("precise", taskConfig->commonData.precise);
insertValues.PutLong("priority", taskConfig->commonData.priority);
insertValues.PutInt("background", taskConfig->commonData.background);
insertValues.PutString("bundle", std::string(taskConfig->bundle.cStr, taskConfig->bundle.len));
insertValues.PutString("url", std::string(taskConfig->url.cStr, taskConfig->url.len));
@ -747,37 +775,37 @@ void GetCommonTaskConfig(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet,
int precise = 0;
int background = 0;
resultSet->GetLong(0, taskId);
resultSet->GetLong(0, taskId); // Line 0 here is 'taskId'
taskConfig.commonData.taskId = static_cast<uint32_t>(taskId);
resultSet->GetLong(1, uid);
resultSet->GetLong(1, uid); // Line 1 here is 'uid'
taskConfig.commonData.uid = static_cast<uint64_t>(uid);
resultSet->GetInt(2, action);
resultSet->GetInt(2, action); // Line 2 here is 'action'
taskConfig.commonData.action = static_cast<uint8_t>(action);
resultSet->GetInt(3, mode);
resultSet->GetInt(3, mode); // Line 3 here is 'mode'
taskConfig.commonData.mode = static_cast<uint8_t>(mode);
resultSet->GetInt(4, cover);
resultSet->GetInt(4, cover); // Line 4 here is 'cover'
taskConfig.commonData.cover = static_cast<bool>(cover);
resultSet->GetInt(5, network);
resultSet->GetInt(5, network); // Line 5 here is 'network'
taskConfig.commonData.network = static_cast<uint8_t>(network);
resultSet->GetInt(6, meterd);
resultSet->GetInt(6, meterd); // Line 6 here is 'meterd'
taskConfig.commonData.meterd = static_cast<bool>(meterd);
resultSet->GetInt(7, roaming);
resultSet->GetInt(7, roaming); // Line 7 here is 'roaming'
taskConfig.commonData.roaming = static_cast<bool>(roaming);
resultSet->GetInt(8, retry);
resultSet->GetInt(8, retry); // Line 8 here is 'retry'
taskConfig.commonData.retry = static_cast<bool>(retry);
resultSet->GetInt(9, redirect);
resultSet->GetInt(9, redirect); // Line 9 here is 'redirect'
taskConfig.commonData.redirect = static_cast<bool>(redirect);
resultSet->GetLong(10, index);
resultSet->GetLong(10, index); // Line 10 here is 'index'
taskConfig.commonData.index = static_cast<uint32_t>(index);
resultSet->GetLong(11, begins);
resultSet->GetLong(11, begins); // Line 11 here is 'begins'
taskConfig.commonData.begins = static_cast<uint64_t>(begins);
resultSet->GetLong(12, ends);
resultSet->GetLong(12, ends); // Line 12 here is 'ends'
taskConfig.commonData.ends = static_cast<int64_t>(ends);
resultSet->GetInt(13, gauge);
resultSet->GetInt(13, gauge); // Line 13 here is 'gauge'
taskConfig.commonData.gauge = static_cast<bool>(gauge);
resultSet->GetInt(14, precise);
resultSet->GetInt(14, precise); // Line 14 here is 'precise'
taskConfig.commonData.precise = static_cast<bool>(precise);
resultSet->GetInt(15, background);
resultSet->GetInt(15, background); // Line 15 here is 'background'
taskConfig.commonData.background = static_cast<bool>(background);
}
@ -803,13 +831,26 @@ int QueryTaskConfigLen()
return len;
}
void QuerySingleTaskConfig(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, TaskConfig &taskConfig)
{
resultSet->GetString(16, taskConfig.bundle); // Line 16 here is 'background'
resultSet->GetString(17, taskConfig.url); // Line 17 here is 'background'
resultSet->GetString(18, taskConfig.title); // Line 18 here is 'background'
resultSet->GetString(19, taskConfig.description); // Line 19 here is 'background'
resultSet->GetString(20, taskConfig.method); // Line 20 here is 'background'
resultSet->GetString(21, taskConfig.headers); // Line 21 here is 'background'
resultSet->GetString(22, taskConfig.data); // Line 22 here is 'background'
resultSet->GetString(23, taskConfig.token); // Line 23 here is 'background'
resultSet->GetString(24, taskConfig.extras); // Line 24 here is 'background'
}
int QueryRequestTaskConfig(const OHOS::NativeRdb::RdbPredicates &rdbPredicates, std::vector<TaskConfig> &taskConfigs)
{
auto resultSet = OHOS::Request::RequestDataBase::GetInstance().Query(rdbPredicates,
{ "task_id", "uid", "action", "mode", "cover", "network", "meterd", "roaming", "retry", "redirect", "idx",
"begins", "ends", "gauge", "precise", "background", "bundle", "url", "titile", "description", "method",
"headers", "data", "token", "extras", "version",
"form_items_len", "file_specs_len", "body_file_names_len" });
"form_items_len", "file_specs_len", "body_file_names_len", "priority" });
int rowCount = 0;
if (resultSet == nullptr || resultSet->GetRowCount(rowCount) != OHOS::NativeRdb::E_OK) {
REQUEST_HILOGE("TaskConfig result set is nullptr or get row count failed");
@ -825,21 +866,16 @@ int QueryRequestTaskConfig(const OHOS::NativeRdb::RdbPredicates &rdbPredicates,
int64_t formItemsLen = 0;
int64_t fileSpecsLen = 0;
int64_t bodyFileNamesLen = 0;
int64_t priority = 0;
GetCommonTaskConfig(resultSet, taskConfig);
resultSet->GetString(16, taskConfig.bundle);
resultSet->GetString(17, taskConfig.url);
resultSet->GetString(18, taskConfig.title);
resultSet->GetString(19, taskConfig.description);
resultSet->GetString(20, taskConfig.method);
resultSet->GetString(21, taskConfig.headers);
resultSet->GetString(22, taskConfig.data);
resultSet->GetString(23, taskConfig.token);
resultSet->GetString(24, taskConfig.extras);
resultSet->GetInt(25, version);
QuerySingleTaskConfig(resultSet, taskConfig);
resultSet->GetInt(25, version); // Line 25 here is 'background'
taskConfig.version = static_cast<uint8_t>(version);
resultSet->GetLong(26, formItemsLen);
resultSet->GetLong(27, fileSpecsLen);
resultSet->GetLong(28, bodyFileNamesLen);
resultSet->GetLong(26, formItemsLen); // Line 26 here is 'background'
resultSet->GetLong(27, fileSpecsLen); // Line 27 here is 'background'
resultSet->GetLong(28, bodyFileNamesLen); // Line 28 here is 'background'
resultSet->GetLong(29, priority); // Line 29 here is 'background'
taskConfig.commonData.priority = static_cast<uint32_t>(priority);
OHOS::NativeRdb::RdbPredicates attachPredicates("task_config_attachment");
attachPredicates.EqualTo("task_id", std::to_string(taskConfig.commonData.taskId))
->And()->EqualTo("uid", std::to_string(taskConfig.commonData.uid));
@ -880,16 +916,16 @@ int QueryTaskConfigAttachment(const OHOS::NativeRdb::RdbPredicates &rdbPredicate
}
if (i < formItemsLen) {
FormItem formItem;
resultSet->GetString(0, formItem.name);
resultSet->GetString(1, formItem.value);
resultSet->GetString(0, formItem.name); // Line 0 here is 'name'
resultSet->GetString(1, formItem.value); // Line 1 here is 'value'
taskConfig.formItems.push_back(std::move(formItem));
}
if (i < fileSpecsLen) {
FileSpec fileSpec;
resultSet->GetString(2, fileSpec.name);
resultSet->GetString(3, fileSpec.path);
resultSet->GetString(4, fileSpec.fileName);
resultSet->GetString(5, fileSpec.mimeType);
resultSet->GetString(2, fileSpec.name); // Line 2 here is 'name'
resultSet->GetString(3, fileSpec.path); // Line 3 here is 'path'
resultSet->GetString(4, fileSpec.fileName); // Line 4 here is 'fileName'
resultSet->GetString(5, fileSpec.mimeType); // Line 5 here is 'mimeType'
taskConfig.fileSpecs.push_back(std::move(fileSpec));
}
if (i < bodyFileNamesLen) {

View File

@ -0,0 +1,28 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[derive(Clone, Copy, PartialEq, Debug)]
pub(crate) enum ErrorCode {
ErrOk = 0,
_UnloadingSA = 1,
IpcSizeTooLarge = 2,
Permission = 201,
SystemApi = 202,
ParameterCheck = 401,
FileOperationErr = 13400001,
Other = 13499999,
TaskEnqueueErr = 21900004,
_TaskModeErr,
TaskNotFound,
TaskStateErr,
}

View File

@ -0,0 +1,50 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// hilog label.
macro_rules! debug {
($($args:tt)*) => {{
use hilog_rust::hilog;
use std::ffi::{c_char, CString};
use $crate::LOG_LABEL;
let log = format!($($args)*);
hilog_rust::info!(LOG_LABEL,"{}",@public(log));
}}
}
macro_rules! info {
($($args:tt)*) => {{
use hilog_rust::hilog;
use std::ffi::{c_char, CString};
use $crate::LOG_LABEL;
let log = format!($($args)*);
hilog_rust::info!(LOG_LABEL,"{}",@public(log));
}}
}
macro_rules! error {
($($args:tt)*) => {{
use hilog_rust::hilog;
use std::ffi::{c_char, CString};
use $crate::LOG_LABEL;
let log = format!($($args)*);
hilog_rust::error!(LOG_LABEL,"{}",@public(log));
}}
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This create implement the request proxy and stub
#![warn(missing_docs, unreachable_pub)]
#![warn(clippy::redundant_clone, clippy::redundant_static_lifetimes)]
#![cfg_attr(not(feature = "oh"), allow(unused))]
#[macro_use]
mod macros;
#[cfg(not(feature = "oh"))]
#[allow(unused_imports)]
#[macro_use]
extern crate log;
#[cfg(feature = "oh")]
#[macro_use]
mod hilog;
mod error;
mod manager;
mod task;
mod utils;
#[cfg(test)]
mod tests;
cfg_oh! {
mod trace;
mod sys_event;
mod service;
pub use service::{RequestService, RequestServiceStub};
/// hilog label
pub const LOG_LABEL: hilog_rust::HiLogLabel = hilog_rust::HiLogLabel {
log_type: hilog_rust::LogType::LogCore,
domain: 0xD001C00,
tag: "RequestService",
};
/// Starts DownloadAbility.
pub fn start() {
info!("Download Ability prepared to be inited");
service::ability::RequestAbility::init();
info!("Download Ability inited");
}
/// Starts DownloadAbility.
pub fn stop() {
info!("Download Ability prepared to be stopped");
service::ability::RequestAbility::stop();
info!("Download Ability stopped");
}
}

View File

@ -0,0 +1,21 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
macro_rules! cfg_oh {
($($item:item)*) => {
$(
#[cfg(feature = "oh")]
$item
)*
}
}

View File

@ -0,0 +1,160 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::HashSet;
use std::fs::File;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use crate::error::ErrorCode;
use crate::manager::TaskManager;
use crate::task::config::{TaskConfig, Version};
use crate::task::info::State;
use crate::task::reason::Reason;
use crate::task::RequestTask;
const MAX_TASK_COUNT: u32 = 300;
const MAX_TASK_COUNT_EACH_APP: u8 = 10;
impl TaskManager {
pub(crate) fn construct_task(
&mut self,
config: TaskConfig,
files: Vec<File>,
body_files: Vec<File>,
) -> ErrorCode {
if files.is_empty() {
return ErrorCode::FileOperationErr;
}
let uid = config.common_data.uid;
let task_id = config.common_data.task_id;
let version = config.version;
debug!(
"TaskManager Construct, uid:{}, task_id:{}, version:{:?}",
uid, task_id, version
);
let app_state = self.app_state(uid, &config.bundle);
let task = RequestTask::constructor(
config,
files,
body_files,
self.recording_rdb_num.clone(),
AtomicBool::new(false),
app_state,
);
match task.conf.version {
Version::API10 => {
if !self.add_task_api10(Arc::new(task)) {
return ErrorCode::TaskEnqueueErr;
}
self.api10_background_task_count += 1;
}
Version::API9 => {
self.add_task_api9(Arc::new(task));
}
}
if let Some(handle) = self.unload_handle.take() {
debug!("TaskManager close sa timing abort");
handle.cancel();
}
ErrorCode::ErrOk
}
pub(crate) fn add_task_api9(&mut self, task: Arc<RequestTask>) {
task.set_status(State::Initialized, Reason::Default);
let task_id = task.conf.common_data.task_id;
let uid = task.conf.common_data.uid;
self.tasks.insert(task_id, task);
match self.app_task_map.get_mut(&uid) {
Some(set) => {
set.insert(task_id);
debug!(
"TaskManager app {} task count:{}, all task count {}",
uid,
set.len(),
self.tasks.len()
);
}
None => {
let mut set = HashSet::new();
set.insert(task_id);
self.app_task_map.insert(uid, set);
debug!(
"TaskManager app {} task count:{}, all task count {}",
uid,
1,
self.tasks.len()
);
}
}
}
pub(crate) fn add_task_api10(&mut self, task: Arc<RequestTask>) -> bool {
let task_id = task.conf.common_data.task_id;
let uid = task.conf.common_data.uid;
if self.api10_background_task_count >= MAX_TASK_COUNT {
error!("TaskManager add v10 task failed, the number of tasks has reached the limit in the system");
return false;
}
match self.app_task_map.get_mut(&uid) {
Some(set) => {
if (set.len() as u8) == MAX_TASK_COUNT_EACH_APP {
error!(
"TaskManager add v10 task failed, the maximum value for each application processing task has been reached");
return false;
}
set.insert(task_id);
task.set_status(State::Initialized, Reason::Default);
self.tasks.insert(task_id, task);
debug!(
"TaskManager app {} task count:{}, all task count {}",
uid,
set.len(),
self.tasks.len()
);
true
}
None => {
let mut set = HashSet::new();
set.insert(task_id);
self.app_task_map.insert(uid, set);
task.set_status(State::Initialized, Reason::Default);
self.tasks.insert(task_id, task);
debug!(
"TaskManager app {} task count:{}, all task count {}",
uid,
1,
self.tasks.len()
);
true
}
}
}
}

View File

@ -0,0 +1,46 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::manager::TaskManager;
use crate::task::info::{DumpAllEachInfo, DumpAllInfo, DumpOneInfo};
impl TaskManager {
pub(crate) fn query_one_task(&self, task_id: u32) -> Option<DumpOneInfo> {
self.tasks.get(&task_id).map(|task| DumpOneInfo {
task_id: task.conf.common_data.task_id,
action: task.conf.common_data.action,
state: task.status.lock().unwrap().state,
reason: task.status.lock().unwrap().reason,
total_size: task
.file_total_size
.load(std::sync::atomic::Ordering::SeqCst),
tran_size: task.progress.lock().unwrap().common_data.total_processed,
url: task.conf.url.clone(),
})
}
pub(crate) fn query_all_task(&self) -> DumpAllInfo {
DumpAllInfo {
vec: self
.tasks
.values()
.map(|task| DumpAllEachInfo {
task_id: task.conf.common_data.task_id,
action: task.conf.common_data.action,
state: task.status.lock().unwrap().state,
reason: task.status.lock().unwrap().reason,
})
.collect(),
}
}
}

View File

@ -0,0 +1,300 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::fmt::Debug;
use std::fs::File;
use ylong_runtime::sync::oneshot::{channel, Sender};
mod construct;
mod dump;
mod pause;
mod query;
mod query_mime_type;
mod remove;
mod resume;
mod search;
mod show;
mod start;
mod stop;
mod touch;
use crate::error::ErrorCode;
use crate::task::config::{Action, TaskConfig};
use crate::task::info::{ApplicationState, DumpAllInfo, DumpOneInfo, TaskInfo};
use crate::utils::filter::Filter;
use crate::utils::Recv;
#[derive(Debug)]
pub(crate) enum EventMessage {
Service(ServiceMessage),
State(StateMessage),
Scheduled(ScheduledMessage),
Task(TaskMessage),
}
impl EventMessage {
pub(crate) fn construct(
config: TaskConfig,
files: Vec<File>,
body_files: Vec<File>,
) -> (Self, Recv<ErrorCode>) {
let (tx, rx) = channel::<ErrorCode>();
(
Self::Service(ServiceMessage::Construct(
Box::new(ConstructMessage {
config,
files,
body_files,
}),
tx,
)),
Recv::new(rx),
)
}
pub(crate) fn pause(uid: u64, task_id: u32) -> (Self, Recv<ErrorCode>) {
let (tx, rx) = channel::<ErrorCode>();
(
Self::Service(ServiceMessage::Pause(uid, task_id, tx)),
Recv::new(rx),
)
}
pub(crate) fn query(task_id: u32, action: Action) -> (Self, Recv<Option<TaskInfo>>) {
let (tx, rx) = channel::<Option<TaskInfo>>();
(
Self::Service(ServiceMessage::Query(task_id, action, tx)),
Recv::new(rx),
)
}
pub(crate) fn query_mime_type(uid: u64, task_id: u32) -> (Self, Recv<String>) {
let (tx, rx) = channel::<String>();
(
Self::Service(ServiceMessage::QueryMimeType(uid, task_id, tx)),
Recv::new(rx),
)
}
pub(crate) fn start(uid: u64, task_id: u32) -> (Self, Recv<ErrorCode>) {
let (tx, rx) = channel::<ErrorCode>();
(
Self::Service(ServiceMessage::Start(uid, task_id, tx)),
Recv::new(rx),
)
}
pub(crate) fn stop(uid: u64, task_id: u32) -> (Self, Recv<ErrorCode>) {
let (tx, rx) = channel::<ErrorCode>();
(
Self::Service(ServiceMessage::Stop(uid, task_id, tx)),
Recv::new(rx),
)
}
pub(crate) fn show(uid: u64, task_id: u32) -> (Self, Recv<Option<TaskInfo>>) {
let (tx, rx) = channel::<Option<TaskInfo>>();
(
Self::Service(ServiceMessage::Show(uid, task_id, tx)),
Recv::new(rx),
)
}
pub(crate) fn search(filter: Filter) -> (Self, Recv<Vec<u32>>) {
let (tx, rx) = channel::<Vec<u32>>();
(
Self::Service(ServiceMessage::Search(filter, tx)),
Recv::new(rx),
)
}
pub(crate) fn touch(uid: u64, task_id: u32, token: String) -> (Self, Recv<Option<TaskInfo>>) {
let (tx, rx) = channel::<Option<TaskInfo>>();
(
Self::Service(ServiceMessage::Touch(uid, task_id, token, tx)),
Recv::new(rx),
)
}
pub(crate) fn remove(uid: u64, task_id: u32) -> (Self, Recv<ErrorCode>) {
let (tx, rx) = channel::<ErrorCode>();
(
Self::Service(ServiceMessage::Remove(uid, task_id, tx)),
Recv::new(rx),
)
}
pub(crate) fn resume(uid: u64, task_id: u32) -> (Self, Recv<ErrorCode>) {
let (tx, rx) = channel::<ErrorCode>();
(
Self::Service(ServiceMessage::Resume(uid, task_id, tx)),
Recv::new(rx),
)
}
pub(crate) fn dump_all() -> (Self, Recv<DumpAllInfo>) {
let (tx, rx) = channel::<DumpAllInfo>();
(Self::Service(ServiceMessage::DumpAll(tx)), Recv::new(rx))
}
pub(crate) fn dump_one(task_id: u32) -> (Self, Recv<Option<DumpOneInfo>>) {
let (tx, rx) = channel::<Option<DumpOneInfo>>();
(
Self::Service(ServiceMessage::DumpOne(task_id, tx)),
Recv::new(rx),
)
}
pub(crate) fn app_state_change(uid: u64, state: ApplicationState) -> Self {
Self::State(StateMessage::AppStateChange(uid, state))
}
pub(crate) fn network_change() -> Self {
Self::State(StateMessage::NetworkChange)
}
}
pub(crate) enum ServiceMessage {
Construct(Box<ConstructMessage>, Sender<ErrorCode>),
Pause(u64, u32, Sender<ErrorCode>),
QueryMimeType(u64, u32, Sender<String>),
Start(u64, u32, Sender<ErrorCode>),
Stop(u64, u32, Sender<ErrorCode>),
Show(u64, u32, Sender<Option<TaskInfo>>),
Remove(u64, u32, Sender<ErrorCode>),
Resume(u64, u32, Sender<ErrorCode>),
Touch(u64, u32, String, Sender<Option<TaskInfo>>),
Query(u32, Action, Sender<Option<TaskInfo>>),
DumpOne(u32, Sender<Option<DumpOneInfo>>),
Search(Filter, Sender<Vec<u32>>),
DumpAll(Sender<DumpAllInfo>),
}
pub(crate) enum TaskMessage {
Finished(u32),
}
pub(crate) enum StateMessage {
NetworkChange,
AppStateChange(u64, ApplicationState),
}
pub(crate) struct ConstructMessage {
pub(crate) config: TaskConfig,
pub(crate) files: Vec<File>,
pub(crate) body_files: Vec<File>,
}
impl Debug for ConstructMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Construct")
.field("uid", &self.config.common_data.uid)
.field("task_id", &self.config.common_data.task_id)
.field("title", &self.config.title)
.field("mode", &self.config.method)
.field("version", &self.config.version)
.finish()
}
}
impl Debug for ServiceMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Construct(message, _) => message.fmt(f),
Self::Pause(uid, task_id, _) => f
.debug_struct("Pause")
.field("uid", uid)
.field("task_id", task_id)
.finish(),
Self::QueryMimeType(uid, task_id, _) => f
.debug_struct("QueryMimeType")
.field("uid", uid)
.field("task_id", task_id)
.finish(),
Self::Start(uid, task_id, _) => f
.debug_struct("Start")
.field("uid", uid)
.field("task_id", task_id)
.finish(),
Self::Stop(uid, task_id, _) => f
.debug_struct("Stop")
.field("uid", uid)
.field("task_id", task_id)
.finish(),
Self::Show(uid, task_id, _) => f
.debug_struct("Show")
.field("uid", uid)
.field("task_id", task_id)
.finish(),
Self::Remove(uid, task_id, _) => f
.debug_struct("Remove")
.field("uid", uid)
.field("task_id", task_id)
.finish(),
Self::Resume(uid, task_id, _) => f
.debug_struct("Resume")
.field("uid", uid)
.field("task_id", task_id)
.finish(),
Self::Touch(uid, task_id, token, _) => f
.debug_struct("Touch")
.field("uid", uid)
.field("task_id", task_id)
.field("token", token)
.finish(),
Self::Query(task_id, action, _) => f
.debug_struct("Query")
.field("task_id", task_id)
.field("action", action)
.finish(),
Self::DumpOne(task_id, _) => {
f.debug_struct("DumpOne").field("task_id", task_id).finish()
}
Self::Search(filter, _) => f.debug_struct("Search").field("filter", filter).finish(),
Self::DumpAll(_) => f.debug_struct("DumpAll").finish(),
}
}
}
impl Debug for TaskMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Finished(task_id) => f
.debug_struct("Finished")
.field("task_id", task_id)
.finish(),
}
}
}
impl Debug for StateMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NetworkChange => f.pad("NetworkChange"),
Self::AppStateChange(uid, state) => f
.debug_struct("AppStateChange")
.field("uid", uid)
.field("state", state)
.finish(),
}
}
}
#[derive(Debug)]
pub(crate) enum ScheduledMessage {
ClearTimeoutTasks,
LogTasks,
Unload,
UpdateBackgroundApp(u64),
}

View File

@ -0,0 +1,37 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::error::ErrorCode;
use crate::manager::TaskManager;
use crate::task::reason::Reason;
impl TaskManager {
pub(crate) fn pause(&mut self, uid: u64, task_id: u32) -> ErrorCode {
debug!("TaskManager pause, uid:{}, task_id:{}", uid, task_id);
match self.get_task(uid, task_id) {
Some(task) => self.pause_task(task, Reason::UserOperation),
None => {
if self.tasks.contains_key(&task_id) {
error!("TaskManager pause a task, task_id:{} exist, but not found in app_task_map, uid:{}", task_id, uid);
} else {
error!(
"TaskManager pause a task, uid:{}, task_id:{} not exist",
uid, task_id
);
}
ErrorCode::TaskStateErr
}
}
}
}

View File

@ -0,0 +1,53 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::manager::TaskManager;
use crate::task::config::Action;
use crate::task::ffi::{CTaskInfo, DeleteCTaskInfo};
use crate::task::info::TaskInfo;
impl TaskManager {
pub(crate) fn query(&self, task_id: u32, query_action: Action) -> Option<TaskInfo> {
debug!(
"TaskManager query, task_id:{}, query_action:{:?}",
task_id, query_action
);
if let Some(task) = self.tasks.get(&task_id) {
if task.conf.common_data.action == query_action || query_action == Action::Any {
debug!("query task info by memory");
let mut task_info = task.show();
task_info.data = "".to_string();
task_info.url = "".to_string();
debug!("query task info is {:?}", task_info);
return Some(task_info);
}
}
debug!("query task info by database");
let c_task_info = unsafe { Query(task_id, query_action) };
if c_task_info.is_null() {
return None;
}
let c_task_info = unsafe { &*c_task_info };
let task_info = TaskInfo::from_c_struct(c_task_info);
debug!("query task info is {:?}", task_info);
unsafe { DeleteCTaskInfo(c_task_info) };
Some(task_info)
}
}
extern "C" {
pub(crate) fn Query(taskId: u32, queryAction: Action) -> *const CTaskInfo;
}

View File

@ -0,0 +1,48 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::show::Show;
use crate::manager::TaskManager;
use crate::task::ffi::DeleteCTaskInfo;
use crate::task::info::TaskInfo;
impl TaskManager {
pub(crate) fn query_mime_type(&self, uid: u64, task_id: u32) -> String {
debug!(
"TaskManager query mime type, uid:{}, task_id:{}",
uid, task_id
);
let task = self.get_task(uid, task_id);
match task {
Some(value) => {
debug!("TaskManager query mime type by memory");
value.query_mime_type()
}
None => {
debug!("TaskManager query mime type: show mime type from database");
let c_task_info = unsafe { Show(task_id, uid) };
if c_task_info.is_null() {
info!("TaskManger query mime type: no task found in database");
return "".into();
}
let c_task_info = unsafe { &*c_task_info };
let task_info = TaskInfo::from_c_struct(c_task_info);
let mime_type = task_info.mime_type;
debug!("TaskManager query mime type: mime type is {:?}", mime_type);
unsafe { DeleteCTaskInfo(c_task_info) };
mime_type
}
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::error::ErrorCode;
use crate::manager::TaskManager;
use crate::task::info::State;
use crate::task::reason::Reason;
impl TaskManager {
pub(crate) fn remove(&mut self, uid: u64, task_id: u32) -> ErrorCode {
if let Some(task) = self.get_task(uid, task_id) {
task.set_status(State::Removed, Reason::UserOperation);
self.after_task_processed(&task);
debug!(
"TaskManager remove a task, uid:{}, task_id:{} success",
uid, task_id
);
ErrorCode::ErrOk
} else {
if self.tasks.contains_key(&task_id) {
error!("TaskManager remove a task, task_id:{} exist, but not found in app_task_map, uid:{}", task_id, uid);
} else {
error!(
"TaskManager remove a task, uid:{}, task_id:{} not exist",
uid, task_id
);
}
ErrorCode::TaskNotFound
}
}
}

View File

@ -0,0 +1,59 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::atomic::Ordering;
use crate::error::ErrorCode;
use crate::manager::TaskManager;
use crate::task::info::State;
cfg_oh! {
use crate::manager::Notifier;
}
impl TaskManager {
pub(crate) fn resume(&mut self, uid: u64, task_id: u32) -> ErrorCode {
debug!("TaskManager resume, uid:{}, task_id:{}", uid, task_id);
if let Some(task) = self.get_task(uid, task_id) {
let state = task.status.lock().unwrap().state;
if state != State::Paused {
error!("can not resume a task which state is not paused");
return ErrorCode::TaskStateErr;
}
error!("resume the task success");
task.resume.store(true, Ordering::SeqCst);
let notify_data = task.build_notify_data();
#[cfg(feature = "oh")]
Notifier::service_front_notify(
"resume".into(),
notify_data,
&self.app_state(task.conf.common_data.uid, &task.conf.bundle),
);
self.start_inner(task);
ErrorCode::ErrOk
} else {
if self.tasks.contains_key(&task_id) {
error!("TaskManager resume a task, task_id:{} exist, but not found in app_task_map, uid:{}", task_id, uid);
} else {
error!(
"TaskManager resume a task, uid:{}, task_id:{} not exist",
uid, task_id
);
}
ErrorCode::TaskStateErr
}
}
}

View File

@ -0,0 +1,43 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::manager::TaskManager;
use crate::utils::c_wrapper::{CFilter, CVectorWrapper, DeleteCVectorWrapper};
use crate::utils::filter::Filter;
impl TaskManager {
pub(crate) fn search(&self, filter: Filter) -> Vec<u32> {
debug!("TaskManager search a task, filter:{:?}", filter);
let mut vec = Vec::<u32>::new();
let c_vector_wrapper = unsafe { Search(filter.to_c_struct()) };
if c_vector_wrapper.ptr.is_null() || c_vector_wrapper.len == 0 {
error!("c_vector_wrapper is null");
return vec;
}
let slice = unsafe {
std::slice::from_raw_parts(c_vector_wrapper.ptr, c_vector_wrapper.len as usize)
};
for item in slice.iter() {
vec.push(*item);
}
debug!("c_vector_wrapper is not null");
unsafe { DeleteCVectorWrapper(c_vector_wrapper.ptr) };
vec
}
}
extern "C" {
pub(crate) fn Search(filter: CFilter) -> CVectorWrapper;
}

View File

@ -0,0 +1,45 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::manager::TaskManager;
use crate::task::ffi::{CTaskInfo, DeleteCTaskInfo};
use crate::task::info::TaskInfo;
impl TaskManager {
pub(crate) fn show(&self, uid: u64, task_id: u32) -> Option<TaskInfo> {
match self.get_task(uid, task_id) {
Some(value) => {
debug!("TaskManager show, uid:{}, task_id:{} success", uid, task_id);
let task_info = value.show();
Some(task_info)
}
None => {
debug!("TaskManager show: show task info from database");
let c_task_info = unsafe { Show(task_id, uid) };
if c_task_info.is_null() {
info!("TaskManger show: no task found in database");
return None;
}
let c_task_info = unsafe { &*c_task_info };
let task_info = TaskInfo::from_c_struct(c_task_info);
debug!("TaskManager show: task info is {:?}", task_info);
unsafe { DeleteCTaskInfo(c_task_info) };
Some(task_info)
}
}
}
}
extern "C" {
pub(crate) fn Show(task_id: u32, uid: u64) -> *const CTaskInfo;
}

View File

@ -0,0 +1,153 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::atomic::Ordering;
use std::sync::Arc;
use crate::error::ErrorCode;
use crate::manager::events::{EventMessage, TaskMessage};
use crate::manager::TaskManager;
use crate::task::config::Version;
use crate::task::info::{ApplicationState, State};
use crate::task::reason::Reason;
use crate::task::request_task::run;
use crate::task::RequestTask;
const MAX_RUNNING_TASK_COUNT_EACH_APP: u32 = 5; // api10
const MAX_RUNNING_TASK_COUNT_API9: u32 = 4;
impl TaskManager {
pub(crate) fn start(&mut self, uid: u64, task_id: u32) -> ErrorCode {
info!("start a task, which task id is {}", task_id);
if let Some(task) = self.get_task(uid, task_id) {
let task_state = task.status.lock().unwrap().state;
if task_state != State::Initialized {
error!("can not start a task which state is {}", task_state as u32);
return ErrorCode::TaskStateErr;
}
self.start_inner(task);
ErrorCode::ErrOk
} else {
if self.tasks.contains_key(&task_id) {
error!("TaskManager start a task, task_id:{} exist, but not found in app_task_map, uid:{}", task_id, uid);
} else {
error!(
"TaskManager start a task, uid:{}, task_id:{} not exist",
uid, task_id
);
}
ErrorCode::TaskStateErr
}
}
pub(crate) fn start_inner(&mut self, task: Arc<RequestTask>) {
if !task.net_work_online() || !task.check_net_work_status() {
error!("check net work failed");
self.after_task_processed(&task);
return;
}
let state = task.status.lock().unwrap().state;
if state != State::Initialized && state != State::Waiting && state != State::Paused {
self.after_task_processed(&task);
return;
}
if self.reach_maximum_running_limit(task.conf.common_data.uid, task.conf.version) {
info!("too many task in running state");
task.set_status(State::Waiting, Reason::RunningTaskMeetLimits);
self.after_task_processed(&task);
return;
}
let (state, reason) = {
let status = task.status.lock().unwrap();
(status.state, status.reason)
};
if state == State::Waiting
&& (reason == Reason::NetWorkOffline || reason == Reason::UnSupportedNetWorkType)
{
task.retry.store(true, Ordering::SeqCst);
task.tries.fetch_add(1, Ordering::SeqCst);
task.set_status(State::Retrying, Reason::Default);
} else {
task.set_status(State::Running, Reason::Default);
}
let task_id = task.conf.common_data.task_id;
let tx = self.tx.clone();
let state = ApplicationState::from(
self.app_state(task.conf.common_data.uid, &task.conf.bundle)
.load(Ordering::Relaxed),
);
let qos_changes = self.qos.insert(&task, state);
self.change_qos(qos_changes);
ylong_runtime::spawn(async move {
run(task.clone()).await;
tx.send(EventMessage::Task(TaskMessage::Finished(
task.conf.common_data.task_id,
)))
});
info!("task {} start success", task_id);
}
fn reach_maximum_running_limit(&self, uid: u64, version: Version) -> bool {
match version {
Version::API10 => {
let mut count = 0;
let tasks = match self.app_task_map.get(&uid) {
Some(v) => v,
None => return false,
};
for task in tasks {
let request_task = match self.tasks.get(task) {
Some(task) => task,
None => {
error!("TaskManager reach_maximum_running_limit task_id:{} not found in uid:{}", task, uid);
continue;
}
};
if request_task.conf.version == Version::API10 {
let state = request_task.status.lock().unwrap().state;
if state == State::Retrying || state == State::Running {
count += 1;
}
if count >= MAX_RUNNING_TASK_COUNT_EACH_APP {
return true;
}
}
}
}
Version::API9 => {
let mut count = 0;
for request_task in self.tasks.values() {
if request_task.conf.version == Version::API9 {
let state = request_task.status.lock().unwrap().state;
if state == State::Retrying || state == State::Running {
count += 1;
}
if count >= MAX_RUNNING_TASK_COUNT_API9 {
return true;
}
}
}
}
}
false
}
}

View File

@ -0,0 +1,51 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::atomic::Ordering;
use crate::error::ErrorCode;
use crate::manager::TaskManager;
use crate::task::info::State;
use crate::task::reason::Reason;
impl TaskManager {
pub(crate) fn stop(&mut self, uid: u64, task_id: u32) -> ErrorCode {
if let Some(task) = self.get_task(uid, task_id) {
if !task.set_status(State::Stopped, Reason::UserOperation) {
let state = task.status.lock().unwrap().state;
error!(
"TaskManager can not stop task_id: {} that state is {:?}",
task_id, state
);
return ErrorCode::TaskStateErr;
}
self.after_task_processed(&task);
debug!(
"TaskManager stop a task, uid: {}, task_id:{} success",
uid, task_id
);
task.resume.store(false, Ordering::SeqCst);
ErrorCode::ErrOk
} else {
if self.tasks.contains_key(&task_id) {
error!("TaskManager stop a task, task_id:{} exist, but not found in app_task_map, uid:{}", task_id, uid);
} else {
error!(
"TaskManager stop a task, uid:{}, task_id:{} not exist",
uid, task_id
);
}
ErrorCode::TaskStateErr
}
}
}

View File

@ -0,0 +1,52 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::manager::TaskManager;
use crate::task::ffi::{CTaskInfo, DeleteCTaskInfo};
use crate::task::info::TaskInfo;
use crate::utils::c_wrapper::CStringWrapper;
impl TaskManager {
pub(crate) fn touch(&self, uid: u64, task_id: u32, token: String) -> Option<TaskInfo> {
debug!("TaskManager touch a task, uid:{}, task_id:{}", uid, task_id);
match self.get_task(uid, task_id) {
Some(value) => {
debug!("touch task info by memory");
if value.conf.token.eq(token.as_str()) {
let mut task_info = value.show();
task_info.bundle = "".to_string();
return Some(task_info);
}
None
}
None => {
debug!("TaskManger touch: touch task_info from database");
let c_task_info = unsafe { Touch(task_id, uid, CStringWrapper::from(&token)) };
if c_task_info.is_null() {
info!("TaskManger touch: no task found in database");
return None;
}
let c_task_info = unsafe { &*c_task_info };
let task_info = TaskInfo::from_c_struct(c_task_info);
debug!("TaskManger touch: task info is {:?}", task_info);
unsafe { DeleteCTaskInfo(c_task_info) };
Some(task_info)
}
}
}
}
extern "C" {
pub(crate) fn Touch(taskId: u32, uid: u64, token: CStringWrapper) -> *const CTaskInfo;
}

View File

@ -0,0 +1,28 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub(crate) mod task_manager;
pub(crate) use task_manager::TaskManager;
pub(crate) mod monitor;
mod unload;
pub(crate) mod events;
pub(crate) mod qos;
pub(crate) mod scheduled;
cfg_oh! {
mod notifier;
pub(crate) use notifier::Notifier;
}

View File

@ -0,0 +1,226 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
use super::TaskManager;
use crate::manager::scheduled;
use crate::task::config::Action;
use crate::task::info::{ApplicationState, Mode, State};
use crate::task::reason::Reason;
cfg_oh! {
use crate::manager::Notifier;
}
impl TaskManager {
pub(crate) fn update_app_state(&mut self, uid: u64, state: ApplicationState) {
if self.app_task_map.get(&uid).is_none() {
return;
}
match state {
ApplicationState::Foreground => {
match self.app_state_map.get(&uid) {
Some(state) => {
state.store(ApplicationState::Foreground as u8, Ordering::SeqCst)
}
None => {
self.app_state_map.insert(
uid,
Arc::new(AtomicU8::new(ApplicationState::Foreground as u8)),
);
}
}
let qos_changes = self.qos.change_state(uid, state);
self.change_qos(qos_changes);
self.update_foreground_app(uid);
}
ApplicationState::Background => {
match self.app_state_map.get(&uid) {
Some(state) => {
state.store(ApplicationState::Background as u8, Ordering::SeqCst)
}
None => {
self.app_state_map.insert(
uid,
Arc::new(AtomicU8::new(ApplicationState::Background as u8)),
);
}
}
let tx = self.tx.clone();
ylong_runtime::spawn(scheduled::update_background_app(uid, tx));
let qos_changes = self.qos.change_state(uid, state);
self.change_qos(qos_changes);
}
ApplicationState::Terminated => {
match self.app_state_map.get(&uid) {
Some(state) => {
state.store(ApplicationState::Terminated as u8, Ordering::SeqCst)
}
None => {
self.app_state_map.insert(
uid,
Arc::new(AtomicU8::new(ApplicationState::Terminated as u8)),
);
}
}
let qos_changes = self.qos.change_state(uid, state);
self.change_qos(qos_changes);
self.update_terminated_app(uid);
}
}
}
fn update_foreground_app(&mut self, uid: u64) {
debug!("TaskManager begin update_foreground_app uid:{}", uid);
let tasks = match self.app_task_map.get(&uid) {
Some(set) => {
let mut v = vec![];
for task_id in set {
match self.tasks.get(task_id) {
Some(task) => {
if task.conf.common_data.mode == Mode::FrontEnd {
v.push(task.clone())
}
}
None => {
error!("TaskManager update_foreground_app uid:{}, task_id:{} not found int tasks", uid, task_id);
return;
}
}
}
v
}
None => {
error!("TaskManager update_foreground_app uid:{} not found", uid);
return;
}
};
tasks.into_iter().for_each(|task| {
let state = task.status.lock().unwrap().state;
let reason = task.status.lock().unwrap().reason;
if state == State::Paused && reason == Reason::AppBackgroundOrTerminate {
info!("Begin try resume task as app switch to background");
task.resume.store(true, Ordering::SeqCst);
let notify_data = task.build_notify_data();
#[cfg(feature = "oh")]
Notifier::service_front_notify(
"resume".into(),
notify_data,
&self.app_state(uid, &task.conf.bundle),
);
self.start_inner(task);
}
});
}
pub(crate) fn update_background_app(&mut self, uid: u64) {
debug!("TaskManager begin update_background_app uid:{}", uid);
if self.app_task_map.get(&uid).is_none() {
return;
}
let tasks = match self.app_task_map.get(&uid) {
Some(set) => {
let mut v = vec![];
for task_id in set {
match self.tasks.get(task_id) {
Some(task) => {
if task.conf.common_data.mode == Mode::FrontEnd {
v.push(task.clone())
}
}
None => {
error!("TaskManager update_foreground_app uid:{}, task_id:{} not found int tasks", uid, task_id);
return;
}
}
}
v
}
None => {
error!("TaskManager update_foreground_app uid:{} not found", uid);
return;
}
};
tasks.into_iter().for_each(|task| {
if task.conf.common_data.action == Action::UpLoad {
task.set_status(State::Failed, Reason::AppBackgroundOrTerminate);
self.after_task_processed(&task);
} else if task.conf.common_data.action == Action::DownLoad {
self.pause_task(task, Reason::AppBackgroundOrTerminate);
}
});
}
fn update_terminated_app(&mut self, uid: u64) {
debug!("TaskManager begin update_terminated_app uid:{}", uid);
let tasks = match self.app_task_map.get(&uid) {
Some(set) => {
let mut v = vec![];
for task_id in set {
match self.tasks.get(task_id) {
Some(task) => {
if task.conf.common_data.mode == Mode::FrontEnd {
v.push(task.clone())
}
}
None => {
error!("TaskManager update_foreground_app uid:{}, task_id:{} not found int tasks", uid, task_id);
return;
}
}
}
v
}
None => {
error!("TaskManager update_foreground_app uid:{} not found", uid);
return;
}
};
tasks.into_iter().for_each(|task| {
task.set_status(State::Failed, Reason::AppBackgroundOrTerminate);
self.after_task_processed(&task);
});
}
pub(crate) fn update_network(&mut self) {
let tasks = self.tasks.values().cloned().collect::<Vec<_>>();
for task in tasks {
if unsafe { IsOnline() } {
self.resume_waiting_task(task.clone());
}
}
}
}
extern "C" {
pub(crate) fn IsOnline() -> bool;
}

View File

@ -0,0 +1,64 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
use crate::service::ability::RequestAbility;
use crate::service::notify::{Event, NotifyEvent};
use crate::task::config::Version;
use crate::task::info::ApplicationState;
use crate::task::notify::NotifyData;
use crate::task::RequestTask;
pub(crate) struct Notifier;
impl Notifier {
pub(crate) fn service_front_notify(
event: String,
notify_data: NotifyData,
app_state: &Arc<AtomicU8>,
) {
let total_processed = notify_data.progress.common_data.total_processed;
let file_total_size: i64 = notify_data.progress.sizes.iter().sum();
if total_processed == 0 && file_total_size < 0 && event.eq("progress") {
return;
}
if ApplicationState::from(app_state.load(Ordering::SeqCst)) != ApplicationState::Foreground
&& (notify_data.version == Version::API10 || event.eq("progress"))
{
return;
}
let event = match event.try_into() {
Ok(event) => event,
Err(e) => {
error!("TaskManager notify try_into failed {:?}", e);
return;
}
};
let event = NotifyEvent::notify(event, notify_data);
RequestAbility::notify().send_event(event);
}
pub(crate) fn remove_notify(task: &Arc<RequestTask>) {
let data = task.build_notify_data();
let event = NotifyEvent::notify(Event::Remove, data);
RequestAbility::notify().send_event(event);
}
pub(crate) fn clear_notify(task: &Arc<RequestTask>) {
let event = NotifyEvent::clear(task.conf.common_data.task_id);
RequestAbility::notify().send_event(event);
}
}

View File

@ -0,0 +1,562 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::mem;
use std::sync::Arc;
use crate::task::info::ApplicationState;
use crate::task::RequestTask;
const HIGH_QOS_MAX: usize = 10;
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub(crate) struct QosCase {
uid: u64,
task_id: u32,
qos_index: u32,
}
impl PartialOrd for QosCase {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for QosCase {
fn cmp(&self, other: &Self) -> Ordering {
if self.uid != other.uid {
return Ordering::Equal;
}
self.qos_index.cmp(&other.qos_index)
}
}
impl QosCase {
fn new(uid: u64, task_id: u32, qos_index: u32) -> Self {
Self {
uid,
task_id,
qos_index,
}
}
}
#[derive(Debug)]
pub(crate) struct QosQueue {
foreground_high_qos_cases: Vec<QosCase>,
foreground_low_qos_cases: HashMap<u64, Vec<QosCase>>,
background_high_qos_cases: Vec<QosCase>,
background_low_qos_cases: HashMap<u64, Vec<QosCase>>,
tasks: HashSet<u32>,
app_state_map: HashMap<u64, ApplicationState>,
app_task_count: HashMap<u64, usize>,
}
#[derive(Debug)]
pub(crate) enum Qos {
High,
Low,
}
impl QosQueue {
pub(crate) fn new() -> Self {
Self {
foreground_high_qos_cases: Vec::with_capacity(HIGH_QOS_MAX),
foreground_low_qos_cases: HashMap::new(),
background_high_qos_cases: Vec::with_capacity(HIGH_QOS_MAX),
background_low_qos_cases: HashMap::new(),
tasks: HashSet::new(),
app_state_map: HashMap::new(),
app_task_count: HashMap::new(),
}
}
pub(crate) fn insert(
&mut self,
task: &Arc<RequestTask>,
app_state: ApplicationState,
) -> Vec<(u32, Qos)> {
let task_id = task.conf.common_data.task_id;
let uid = task.conf.common_data.uid;
let priority = task.conf.common_data.priority;
if self.tasks.contains(&task_id) {
error!(
"Qos insert a task twice, uid:{} task_id:{} priority:{}",
uid, task_id, priority
);
return vec![];
}
if app_state == ApplicationState::Terminated {
error!(
"Qos insert a terminated task, uid:{} task_id:{} priority:{}",
uid, task_id, priority
);
return vec![];
}
debug!(
"Qos insert a task, uid:{} task_id:{} priority:{}",
uid, task_id, priority
);
self.tasks.insert(task_id);
match self.app_task_count.get_mut(&uid) {
Some(count) => *count += 1,
None => {
self.app_task_count.insert(uid, 1);
}
}
let case = QosCase::new(uid, task_id, priority);
match self.app_state_map.get(&uid) {
Some(state) => {
if *state != app_state {
error!(
"Qos app_state_map state:{:?} not eq to inserted app_state:{:?}",
state, app_state
);
let mut qos_changes = self.change_state(uid, app_state);
qos_changes.extend(self.insert_inner(case, app_state));
qos_changes
} else {
self.insert_inner(case, app_state)
}
}
None => {
self.app_state_map.insert(uid, app_state);
self.insert_inner(case, app_state)
}
}
}
fn insert_inner(&mut self, case: QosCase, state: ApplicationState) -> Vec<(u32, Qos)> {
match state {
ApplicationState::Foreground => self.frontground_insert(case, state),
ApplicationState::Background => self.background_insert(case, state),
_ => unreachable!(),
}
}
fn frontground_insert(&mut self, case: QosCase, state: ApplicationState) -> Vec<(u32, Qos)> {
if self.foreground_high_qos_cases.len() < HIGH_QOS_MAX {
let mut qos_changes = Vec::new();
qos_changes.push((case.task_id, Qos::High));
self.foreground_high_qos_cases.push(case);
if self.background_high_qos_cases.len() + self.foreground_high_qos_cases.len()
> HIGH_QOS_MAX
{
self.background_high_qos_cases.sort();
let down_grade_case = self.background_high_qos_cases.pop().unwrap();
qos_changes.push((down_grade_case.task_id, Qos::Low));
match self.background_low_qos_cases.get_mut(&down_grade_case.uid) {
Some(low_qos_cases) => {
low_qos_cases.push(down_grade_case);
}
None => {
let mut low_qos_cases = Vec::new();
let uid = down_grade_case.uid;
low_qos_cases.push(down_grade_case);
self.background_low_qos_cases.insert(uid, low_qos_cases);
}
}
}
qos_changes
} else {
self.contest_insert(case, state)
}
}
fn background_insert(&mut self, case: QosCase, state: ApplicationState) -> Vec<(u32, Qos)> {
if self.background_high_qos_cases.len() + self.foreground_high_qos_cases.len()
< HIGH_QOS_MAX
{
let task_id = case.task_id;
self.background_high_qos_cases.push(case);
vec![(task_id, Qos::High)]
} else {
self.contest_insert(case, state)
}
}
fn contest_insert(&mut self, mut case: QosCase, state: ApplicationState) -> Vec<(u32, Qos)> {
let high_qos_cases = match state {
ApplicationState::Foreground => &mut self.foreground_high_qos_cases,
ApplicationState::Background => &mut self.background_high_qos_cases,
ApplicationState::Terminated => unreachable!(),
};
let low_qos_cases = match state {
ApplicationState::Foreground => &mut self.foreground_low_qos_cases,
ApplicationState::Background => &mut self.background_low_qos_cases,
ApplicationState::Terminated => unreachable!(),
};
let mut qos_changes = Vec::new();
let mut down_grade_case = &case;
let mut swap_case_index_opt = None;
for (i, swap_case) in high_qos_cases
.iter()
.enumerate()
.filter(|(_, swap)| swap.uid == case.uid)
{
if down_grade_case.qos_index < swap_case.qos_index {
down_grade_case = swap_case;
swap_case_index_opt = Some(i)
}
}
if let Some(i) = swap_case_index_opt {
qos_changes.push((case.task_id, Qos::High));
mem::swap(&mut case, high_qos_cases.get_mut(i).unwrap());
}
qos_changes.push((case.task_id, Qos::Low));
match low_qos_cases.get_mut(&case.uid) {
Some(cases) => {
cases.push(case);
}
None => {
let mut cases = Vec::new();
let uid = case.uid;
cases.push(case);
low_qos_cases.insert(uid, cases);
}
}
qos_changes
}
pub(crate) fn remove(&mut self, uid: u64, task_id: u32) -> Vec<(u32, Qos)> {
let state = match self.app_state_map.get(&uid) {
None => {
error!("Qos can not find app_state, uid:{}", uid);
return vec![];
}
Some(state) => state,
};
if !self.tasks.remove(&task_id) {
debug!("Qos remove task_id:{} that not exist", task_id);
return vec![];
}
debug!("Qos remove uid:{} task_id:{}", uid, task_id);
match self.app_task_count.get_mut(&uid) {
Some(count) => {
*count -= 1;
if *count == 0 {
self.app_task_count.remove(&uid);
}
}
None => {
error!(
"Qos remove task_id:{}, but uid:{} count task 0",
task_id, uid
);
}
}
match state {
ApplicationState::Foreground => self.foreground_remove(uid, task_id),
ApplicationState::Background => self.background_remove(uid, task_id),
ApplicationState::Terminated => unreachable!(),
}
}
fn foreground_remove(&mut self, uid: u64, task_id: u32) -> Vec<(u32, Qos)> {
let mut qos_changes = vec![];
for i in 0..self.foreground_high_qos_cases.len() {
if self.foreground_high_qos_cases[i].task_id == task_id {
self.foreground_high_qos_cases.remove(i);
for low_qos_cases in self.foreground_low_qos_cases.values_mut() {
low_qos_cases.sort_by(|a, b| b.qos_index.cmp(&a.qos_index));
if let Some(case) = low_qos_cases.pop() {
qos_changes.push((case.task_id, Qos::High));
self.foreground_high_qos_cases.push(case);
return qos_changes;
}
}
for low_qos_cases in self.background_low_qos_cases.values_mut() {
low_qos_cases.sort_by(|a, b| b.qos_index.cmp(&a.qos_index));
if let Some(case) = low_qos_cases.pop() {
qos_changes.push((case.task_id, Qos::High));
self.background_high_qos_cases.push(case);
return qos_changes;
}
}
return qos_changes;
}
}
if let Some(set) = self.foreground_low_qos_cases.get_mut(&uid) {
for i in 0..set.len() {
if set[i].task_id == task_id {
set.remove(i);
}
}
}
qos_changes
}
fn background_remove(&mut self, uid: u64, task_id: u32) -> Vec<(u32, Qos)> {
let mut qos_changes = vec![];
for i in 0..self.background_high_qos_cases.len() {
if self.background_high_qos_cases[i].task_id == task_id {
self.background_high_qos_cases.remove(i);
for low_qos_cases in self.background_low_qos_cases.values_mut() {
low_qos_cases.sort_by(|a, b| b.qos_index.cmp(&a.qos_index));
if let Some(case) = low_qos_cases.pop() {
qos_changes.push((case.task_id, Qos::High));
self.background_high_qos_cases.push(case);
return qos_changes;
}
}
return qos_changes;
}
}
if let Some(set) = self.background_low_qos_cases.get_mut(&uid) {
for i in 0..set.len() {
if set[i].task_id == task_id {
set.remove(i);
}
}
}
qos_changes
}
pub(crate) fn change_state(
&mut self,
uid: u64,
new_state: ApplicationState,
) -> Vec<(u32, Qos)> {
let state = match self.app_state_map.get(&uid) {
None => return vec![],
Some(state) => {
if *state == new_state {
error!("Qos change state with the same state");
return vec![];
} else {
*state
}
}
};
debug!(
"Qos change state uid:{}, state:{:?}, new_state:{:?}",
uid, state, new_state
);
self.app_state_map.insert(uid, new_state);
match new_state {
ApplicationState::Foreground => self.state_turn_to_foreground(uid),
ApplicationState::Background => self.state_turn_to_background(uid),
ApplicationState::Terminated => self.state_turn_to_terminated(uid, state),
}
}
fn state_turn_to_foreground(&mut self, uid: u64) -> Vec<(u32, Qos)> {
let mut qos_changes = vec![];
let high_qos_cases = self
.background_high_qos_cases
.iter()
.cloned()
.filter(|case| case.uid == uid);
self.foreground_high_qos_cases.extend(high_qos_cases);
self.background_high_qos_cases
.retain(|case| case.uid != uid);
if let Some(mut low_qos_cases) = self.background_low_qos_cases.remove(&uid) {
low_qos_cases.sort_by(|a, b| b.qos_index.cmp(&a.qos_index));
while self.foreground_high_qos_cases.len() < HIGH_QOS_MAX {
if let Some(case) = low_qos_cases.pop() {
qos_changes.extend(self.frontground_insert(case, ApplicationState::Foreground));
} else {
break;
}
}
if !low_qos_cases.is_empty() {
self.foreground_low_qos_cases.insert(uid, low_qos_cases);
}
}
qos_changes
}
fn state_turn_to_background(&mut self, uid: u64) -> Vec<(u32, Qos)> {
let mut qos_changes = vec![];
if let Some(low_qos_cases) = self.foreground_low_qos_cases.remove(&uid) {
self.background_low_qos_cases.insert(uid, low_qos_cases);
}
let mut high_qos_cases = self
.foreground_high_qos_cases
.iter()
.cloned()
.filter(|case| case.uid == uid)
.collect::<Vec<_>>();
self.foreground_high_qos_cases
.retain(|case| case.uid != uid);
'a: for low_qos_cases in self.foreground_low_qos_cases.values_mut() {
low_qos_cases.sort_by(|a, b| b.qos_index.cmp(&a.qos_index));
while self.foreground_high_qos_cases.len() < HIGH_QOS_MAX {
if let Some(case) = low_qos_cases.pop() {
qos_changes.push((case.task_id, Qos::High));
self.foreground_high_qos_cases.push(case);
} else {
break 'a;
}
}
}
self.foreground_low_qos_cases
.retain(|_, cases| !cases.is_empty());
if self.foreground_high_qos_cases.len() < 10 {
high_qos_cases.sort_by(|a, b| b.qos_index.cmp(&a.qos_index));
while self.background_high_qos_cases.len() + self.foreground_high_qos_cases.len()
< HIGH_QOS_MAX
{
if let Some(case) = high_qos_cases.pop() {
self.background_high_qos_cases.push(case);
} else {
break;
}
}
}
qos_changes.extend(high_qos_cases.iter().map(|case| (case.task_id, Qos::Low)));
if !high_qos_cases.is_empty() {
match self.background_low_qos_cases.get_mut(&uid) {
Some(low_qos_cases) => {
low_qos_cases.extend(high_qos_cases);
}
None => {
let low_qos_cases = high_qos_cases.into_iter().collect();
self.background_low_qos_cases.insert(uid, low_qos_cases);
}
}
}
qos_changes
}
fn state_turn_to_terminated(
&mut self,
uid: u64,
old_state: ApplicationState,
) -> Vec<(u32, Qos)> {
let mut qos_changes = vec![];
self.app_state_map.remove(&uid);
self.app_task_count.remove(&uid);
match old_state {
ApplicationState::Background => {
self.background_high_qos_cases
.iter()
.filter(|case| case.uid == uid)
.for_each(|case| {
self.tasks.remove(&case.task_id);
});
self.background_high_qos_cases
.retain(|case| case.uid != uid);
'a: for low_qos_cases in self.background_low_qos_cases.values_mut() {
low_qos_cases.sort_by(|a, b| b.qos_index.cmp(&a.qos_index));
while self.background_high_qos_cases.len()
+ self.foreground_high_qos_cases.len()
< HIGH_QOS_MAX
{
if let Some(case) = low_qos_cases.pop() {
qos_changes.push((case.task_id, Qos::High));
self.background_high_qos_cases.push(case);
} else {
break 'a;
}
}
}
if let Some(remove_tasks) = self.background_low_qos_cases.remove(&uid) {
remove_tasks.into_iter().for_each(|case| {
self.tasks.remove(&case.task_id);
})
}
}
ApplicationState::Foreground => {
self.foreground_high_qos_cases
.iter()
.filter(|case| case.uid == uid)
.for_each(|case| {
self.tasks.remove(&case.task_id);
});
self.foreground_high_qos_cases
.retain(|case| case.uid != uid);
'a: for low_qos_cases in self.foreground_low_qos_cases.values_mut() {
low_qos_cases.sort_by(|a, b| b.qos_index.cmp(&a.qos_index));
while self.foreground_high_qos_cases.len() < HIGH_QOS_MAX {
if let Some(case) = low_qos_cases.pop() {
qos_changes.push((case.task_id, Qos::High));
self.foreground_high_qos_cases.push(case);
} else {
break 'a;
}
}
}
if let Some(remove_tasks) = self.foreground_low_qos_cases.remove(&uid) {
remove_tasks.into_iter().for_each(|case| {
self.tasks.remove(&case.task_id);
})
}
}
_ => unreachable!(),
}
qos_changes
}
}

View File

@ -0,0 +1,122 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Duration;
use ylong_runtime::sync::mpsc::UnboundedSender;
use super::events::{EventMessage, ScheduledMessage};
use super::TaskManager;
use crate::task::config::Version;
use crate::task::info::State;
use crate::task::reason::Reason;
use crate::task::RequestTask;
use crate::utils::get_current_timestamp;
const MILLISECONDS_IN_ONE_DAY: u64 = 24 * 60 * 60 * 1000;
const MILLISECONDS_IN_ONE_MONTH: u64 = 30 * 24 * 60 * 60 * 1000;
const CLEAR_INTERVAL: u64 = 30 * 60;
const LOG_INTERVAL: u64 = 5 * 60;
const UNLOAD_WAITING: u64 = 60;
const BACKGROUND_TASK_STOP_INTERVAL: u64 = 60;
// monitor tasks, tasks in waiting state turn to stop after one day, tasks in
// other state turn to stop after one month.
pub(crate) async fn clear_timeout_tasks(tx: UnboundedSender<EventMessage>) {
loop {
ylong_runtime::time::sleep(Duration::from_secs(CLEAR_INTERVAL)).await;
let _ = tx.send(EventMessage::Scheduled(ScheduledMessage::ClearTimeoutTasks));
}
}
pub(crate) async fn log_all_task_info(tx: UnboundedSender<EventMessage>) {
loop {
ylong_runtime::time::sleep(Duration::from_secs(LOG_INTERVAL)).await;
let _ = tx.send(EventMessage::Scheduled(ScheduledMessage::LogTasks));
}
}
pub(crate) async fn unload_sa(tx: UnboundedSender<EventMessage>) {
ylong_runtime::time::sleep(Duration::from_secs(UNLOAD_WAITING)).await;
let _ = tx.send(EventMessage::Scheduled(ScheduledMessage::Unload));
}
pub(crate) async fn update_background_app(uid: u64, tx: UnboundedSender<EventMessage>) {
ylong_runtime::time::sleep(Duration::from_secs(BACKGROUND_TASK_STOP_INTERVAL)).await;
let _ = tx.send(EventMessage::Scheduled(
ScheduledMessage::UpdateBackgroundApp(uid),
));
}
impl TaskManager {
pub(crate) fn clear_timeout_tasks(&mut self) {
let mut remove_tasks = Vec::<Arc<RequestTask>>::new();
for task in self.tasks.values() {
let current_time = get_current_timestamp();
let (state, time) = {
let guard = task.status.lock().unwrap();
(guard.state, guard.waitting_network_time)
};
if state == State::Waiting {
if let Some(t) = time {
if current_time - t > MILLISECONDS_IN_ONE_DAY {
task.set_status(State::Stopped, Reason::WaittingNetWorkOneday);
remove_tasks.push(task.clone());
}
}
}
if task.conf.version == Version::API9 {
continue;
}
if current_time - task.ctime > MILLISECONDS_IN_ONE_MONTH {
task.set_status(State::Stopped, Reason::TaskSurvivalOneMonth);
remove_tasks.push(task.clone());
continue;
}
}
for task in remove_tasks {
self.after_task_processed(&task);
}
}
pub(crate) fn log_all_task_info(&self) {
let api10_background_task_count = self.api10_background_task_count;
let recording_rdb_num = self.recording_rdb_num.load(Ordering::SeqCst);
info!(
"dump all task info, api10_background_task_count:{}, recording_rdb_num:{}",
api10_background_task_count, recording_rdb_num
);
for (task_id, task) in self.tasks.iter() {
let task_status = task.status.lock().unwrap();
info!("dump task message, task_id:{}, action:{}, mode:{}, bundle name:{}, task_status:{:?}",
task_id, task.conf.common_data.action as u8, task.conf.common_data.mode as u8, task.conf.bundle, *task_status);
}
}
pub(crate) fn schedule_unload_sa(&mut self) {
debug!("TaskManage clock 60s to close sa");
let tx = self.tx.clone();
match self.unload_handle.take() {
Some(handle) => {
handle.cancel();
self.unload_handle = Some(ylong_runtime::spawn(unload_sa(tx)));
}
None => {
self.unload_handle = Some(ylong_runtime::spawn(unload_sa(tx)));
}
}
}
}

View File

@ -0,0 +1,456 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::{HashMap, HashSet};
use std::sync::atomic::{AtomicU32, AtomicU8, Ordering};
use std::sync::Arc;
use ylong_runtime::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
use ylong_runtime::task::JoinHandle;
use super::events::{
ConstructMessage, EventMessage, ScheduledMessage, ServiceMessage, StateMessage, TaskMessage,
};
use super::qos::{Qos, QosQueue};
use super::scheduled;
use crate::error::ErrorCode;
use crate::task::config::Version;
use crate::task::info::{ApplicationState, State};
use crate::task::reason::Reason;
use crate::task::request_task::RequestTask;
use crate::utils::c_wrapper::CStringWrapper;
cfg_oh! {
use crate::manager::Notifier;
}
pub(crate) struct TaskManager {
pub(crate) tasks: HashMap<u32, Arc<RequestTask>>,
pub(crate) qos: QosQueue,
pub(crate) app_task_map: HashMap<u64, HashSet<u32>>,
pub(crate) app_state_map: HashMap<u64, Arc<AtomicU8>>,
pub(crate) restoring: bool,
pub(crate) api10_background_task_count: u32,
pub(crate) unload_handle: Option<JoinHandle<()>>,
pub(crate) recording_rdb_num: Arc<AtomicU32>,
pub(crate) tx: UnboundedSender<EventMessage>,
pub(crate) rx: UnboundedReceiver<EventMessage>,
}
#[derive(Clone)]
pub(crate) struct TaskManagerEntry {
tx: UnboundedSender<EventMessage>,
}
impl TaskManagerEntry {
fn new(tx: UnboundedSender<EventMessage>) -> Self {
Self { tx }
}
pub(crate) fn send_event(&self, event: EventMessage) -> bool {
if self.tx.send(event).is_err() {
error!("Sends TaskManager event failed, or TaskManager is unloading");
return false;
}
true
}
}
impl TaskManager {
pub(crate) fn init() -> TaskManagerEntry {
debug!("TaskManager init");
ylong_runtime::builder::RuntimeBuilder::new_multi_thread()
.worker_num(4)
.build_global()
.unwrap();
let (tx, rx) = unbounded_channel();
let mut task_manager = Self::new(tx.clone(), rx);
// Considers update invalid task in database to FAILED state here?.
task_manager.restore_all_tasks(task_manager.recording_rdb_num.clone());
ylong_runtime::spawn(scheduled::clear_timeout_tasks(task_manager.tx.clone()));
ylong_runtime::spawn(scheduled::log_all_task_info(task_manager.tx.clone()));
ylong_runtime::spawn(task_manager.run());
TaskManagerEntry::new(tx)
}
fn new(tx: UnboundedSender<EventMessage>, rx: UnboundedReceiver<EventMessage>) -> Self {
TaskManager {
qos: QosQueue::new(),
tasks: HashMap::new(),
app_task_map: HashMap::new(),
app_state_map: HashMap::new(),
unload_handle: None,
restoring: false,
api10_background_task_count: 0,
recording_rdb_num: Arc::new(AtomicU32::new(0)),
rx,
tx,
}
}
async fn run(mut self) {
loop {
let recv = match self.rx.recv().await {
Ok(message) => message,
Err(e) => {
error!("TaskManager recv error {:?}", e);
continue;
}
};
match recv {
EventMessage::Service(message) => self.handle_service_command(message),
EventMessage::State(message) => self.handle_state_change(message),
EventMessage::Task(message) => self.handle_request_task(message),
EventMessage::Scheduled(message) => {
if self.handle_scheduled_task(message) {
info!("TaskManager unload succeed");
// If unload_sa success, breaks this loop.
return;
}
}
}
debug!("TaskManager handle message done");
}
}
fn handle_request_task(&mut self, message: TaskMessage) {
debug!("TaskManager handle task_message {:?}", message);
match message {
TaskMessage::Finished(task_id) => {
let task = match self.tasks.get(&task_id) {
Some(task) => task.clone(),
None => return,
};
self.after_task_processed(&task);
}
}
}
fn handle_scheduled_task(&mut self, message: ScheduledMessage) -> bool {
debug!("TaskManager handle scheduled_message {:?}", message);
match message {
ScheduledMessage::ClearTimeoutTasks => self.clear_timeout_tasks(),
ScheduledMessage::LogTasks => self.log_all_task_info(),
ScheduledMessage::Unload => return self.unload_sa(),
ScheduledMessage::UpdateBackgroundApp(uid) => self.update_background_app(uid),
}
false
}
fn handle_state_change(&mut self, message: StateMessage) {
debug!("TaskManager handle state_message {:?}", message);
match message {
StateMessage::NetworkChange => {
self.update_network();
}
StateMessage::AppStateChange(uid, state) => {
self.update_app_state(uid, state);
}
}
}
fn handle_service_command(&mut self, message: ServiceMessage) {
debug!("TaskManager handle service_message {:?}", message);
match message {
ServiceMessage::Construct(construct_message, tx) => {
let ConstructMessage {
config,
files,
body_files,
} = *construct_message;
let error_code = self.construct_task(config, files, body_files);
let _ = tx.send(error_code);
}
ServiceMessage::Pause(uid, task_id, tx) => {
let error_code = self.pause(uid, task_id);
let _ = tx.send(error_code);
}
ServiceMessage::Resume(uid, task_id, tx) => {
let error_code = self.resume(uid, task_id);
let _ = tx.send(error_code);
}
ServiceMessage::Start(uid, task_id, tx) => {
let error_code = self.start(uid, task_id);
let _ = tx.send(error_code);
}
ServiceMessage::Stop(uid, task_id, tx) => {
let error_code = self.stop(uid, task_id);
let _ = tx.send(error_code);
}
ServiceMessage::Show(uid, task_id, tx) => {
let task_info = self.show(uid, task_id);
let _ = tx.send(task_info);
}
ServiceMessage::Query(task_id, query_action, tx) => {
let task_info = self.query(task_id, query_action);
let _ = tx.send(task_info);
}
ServiceMessage::Search(filter, tx) => {
let v = self.search(filter);
let _ = tx.send(v);
}
ServiceMessage::Touch(uid, task_id, token, tx) => {
let task_info = self.touch(uid, task_id, token);
let _ = tx.send(task_info);
}
ServiceMessage::Remove(uid, task_id, tx) => {
let error_code = self.remove(uid, task_id);
let _ = tx.send(error_code);
}
ServiceMessage::DumpAll(tx) => {
let dump_all_info = self.query_all_task();
let _ = tx.send(dump_all_info);
}
ServiceMessage::DumpOne(task_id, tx) => {
let dump_one_info = self.query_one_task(task_id);
let _ = tx.send(dump_one_info);
}
ServiceMessage::QueryMimeType(uid, task_id, tx) => {
let s = self.query_mime_type(uid, task_id);
let _ = tx.send(s);
}
}
}
pub(crate) fn app_state(&mut self, uid: u64, bundle: &str) -> Arc<AtomicU8> {
match self.app_state_map.get(&uid) {
Some(state) => state.clone(),
None => {
let top_bundle = unsafe { GetTopBundleName() };
let top_bundle = top_bundle.to_string();
debug!(
"TaskManager try get app_state uid:{} from top_bundle {}",
uid, top_bundle
);
if top_bundle == bundle {
let state = Arc::new(AtomicU8::new(ApplicationState::Foreground as u8));
self.app_state_map.insert(uid, state.clone());
state
} else {
let state = Arc::new(AtomicU8::new(ApplicationState::Background as u8));
self.app_state_map.insert(uid, state.clone());
state
}
}
}
}
pub(crate) fn get_task(&self, uid: u64, task_id: u32) -> Option<Arc<RequestTask>> {
self.app_task_map
.get(&uid)
.and_then(|set| set.get(&task_id))
.and_then(|task_id| self.tasks.get(task_id).cloned())
}
fn process_waiting_task(&mut self, uid: u64, version: Version) {
match version {
Version::API10 => {
let tasks = match self.app_task_map.get(&uid) {
Some(v) => v.iter().copied().collect::<Vec<_>>(),
None => return,
};
for task in tasks {
let request_task = match self.tasks.get(&task) {
Some(task) => task,
None => {
error!(
"TaskManager process waiting task, task_id:{} not found",
task
);
continue;
}
};
if request_task.conf.version == Version::API10 {
let state = request_task.status.lock().unwrap().state;
if state == State::Waiting {
debug!(
"TaskManager begin process v10 task_id:{} which in waitting state",
task
);
self.start_inner(request_task.clone());
return;
}
}
}
}
Version::API9 => {
for task in self.tasks.values() {
if task.conf.version == Version::API9 {
let state = task.status.lock().unwrap().state;
if state == State::Waiting {
debug!(
"TaskManager begin process v9 task_id:{} which in waitting state",
task.conf.common_data.task_id
);
let task = task.clone();
self.start_inner(task);
return;
}
}
}
}
}
}
pub(crate) fn after_task_processed(&mut self, task: &Arc<RequestTask>) {
let state = task.status.lock().unwrap().state;
if state != State::Completed
&& state != State::Failed
&& state != State::Removed
&& state != State::Stopped
{
return;
}
debug!(
"TaskManager remove task_id:{} from map",
task.conf.common_data.task_id
);
let remove_task = self.tasks.remove(&task.conf.common_data.task_id).unwrap();
let uid = &task.conf.common_data.uid;
match self.app_task_map.get_mut(uid) {
Some(map) => {
map.remove(&task.conf.common_data.task_id);
}
None => {
error!("TaskManager after_task_processed get uid:{} failed", uid);
return;
}
}
match self.app_task_map.get(&task.conf.common_data.uid) {
Some(map) => {
if map.is_empty() {
self.app_task_map.remove(&task.conf.common_data.uid);
self.app_state_map.remove(&remove_task.conf.common_data.uid);
}
}
None => {
error!("TaskManger where is my map");
return;
}
}
if remove_task.conf.version == Version::API10 {
self.api10_background_task_count -= 1;
}
let app_state = ApplicationState::from(remove_task.app_state.load(Ordering::SeqCst));
if !(app_state == ApplicationState::Background
&& remove_task.conf.version == Version::API10)
{
#[cfg(feature = "oh")]
Notifier::remove_notify(&remove_task);
}
// Notifies NotifyManager to remove RemoteObj when task has been removed.
#[cfg(feature = "oh")]
Notifier::clear_notify(&remove_task);
let map = self
.qos
.remove(task.conf.common_data.uid, task.conf.common_data.task_id);
self.change_qos(map);
if self.check_unload_sa() {
self.schedule_unload_sa();
} else {
self.process_waiting_task(remove_task.conf.common_data.uid, remove_task.conf.version);
}
}
pub(crate) fn pause_task(&self, task: Arc<RequestTask>, reason: Reason) -> ErrorCode {
let uid = task.conf.common_data.uid;
let task_id = task.conf.common_data.task_id;
if !task.set_status(State::Paused, reason) {
let state = task.status.lock().unwrap();
error!(
"TaskManager pause a task, uid:{}, task_id:{} failed which state is {:?}",
uid, task_id, state
);
ErrorCode::TaskStateErr
} else {
task.resume.store(false, Ordering::SeqCst);
debug!(
"TaskManager pause a task, uid:{}, task_id:{} success",
uid, task_id
);
ErrorCode::ErrOk
}
}
pub(crate) fn resume_waiting_task(&mut self, task: Arc<RequestTask>) {
let state = task.status.lock().unwrap().state;
if state == State::Waiting && task.is_satisfied_configuration() {
info!("Begin try resume task as network condition resume");
task.resume.store(true, Ordering::SeqCst);
let notify_data = task.build_notify_data();
#[cfg(feature = "oh")]
Notifier::service_front_notify(
"resume".into(),
notify_data,
&self.app_state(task.conf.common_data.uid, &task.conf.bundle),
);
self.start_inner(task.clone());
}
}
pub(crate) fn change_qos(&mut self, new_qos: Vec<(u32, Qos)>) {
for (task_id, qos) in new_qos.iter() {
if let Some(task) = self.tasks.get(task_id) {
match qos {
Qos::High => {
info!("Qos task_id:{} set to High Qos", task_id);
task.rate_limiting.store(false, Ordering::SeqCst);
}
Qos::Low => {
info!("Qos task_id:{} set to Low Qos", task_id);
task.rate_limiting.store(true, Ordering::SeqCst);
}
}
}
}
}
}
extern "C" {
pub(crate) fn GetTopBundleName() -> CStringWrapper;
}

View File

@ -0,0 +1,217 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::HashSet;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use std::sync::Arc;
use super::TaskManager;
use crate::manager::monitor::IsOnline;
use crate::task::config::{TaskConfig, Version};
use crate::task::ffi::CTaskConfig;
use crate::task::info::State;
use crate::task::RequestTask;
impl TaskManager {
pub(crate) fn check_unload_sa(&self) -> bool {
if !self.rx.is_empty() {
return false;
}
if !self.tasks.is_empty() && self.network_check_unload_sa() {
return false;
}
if self.recording_rdb_num.load(Ordering::SeqCst) != 0 {
return false;
}
if !self.rx.is_empty() {
return false;
}
true
}
pub(crate) fn unload_sa(&mut self) -> bool {
#[cfg(feature = "oh")]
const REQUEST_SERVICE_ID: i32 = 3706;
if !self.check_unload_sa() {
debug!("Triggers unload sa, but cannot unload now");
return false;
}
self.rx.close();
info!("unload SA");
if !self.tasks.is_empty() {
self.record_all_task_config();
}
#[cfg(feature = "oh")]
let samgr_proxy = rust_samgr::get_systemability_manager();
// failed logic?
#[cfg(feature = "oh")]
let _ = samgr_proxy
.unload_systemability(REQUEST_SERVICE_ID)
.map_err(|e| error!("unload SA failed, err is {:?}", e));
true
}
pub(crate) fn restore_all_tasks(&mut self, recording_rdb_num: Arc<AtomicU32>) {
if self.restoring {
return;
}
self.restoring = true;
if let Some(config_list) = self.query_all_task_config() {
info!(
"RSA query task config list len: {} in database",
config_list.len()
);
for config in config_list.into_iter() {
debug!("RSA query task config is {:?}", config);
let uid = config.common_data.uid;
let task_id = config.common_data.task_id;
let token = config.token.clone();
if let Some(task_info) = self.touch(uid, task_id, token) {
let state = State::from(task_info.progress.common_data.state);
if state != State::Waiting && state != State::Paused {
continue;
}
let app_state = self.app_state(uid, &config.bundle);
let request_task = RequestTask::restore_task(
config,
task_info,
recording_rdb_num.clone(),
AtomicBool::new(false),
app_state,
);
let task = Arc::new(request_task);
self.restore_task(task.clone());
if unsafe { IsOnline() } {
self.resume_waiting_task(task.clone());
}
}
unsafe { CleanTaskConfigTable(task_id, uid) };
}
} else {
self.schedule_unload_sa();
}
self.restoring = false;
}
fn record_all_task_config(&mut self) {
debug!("record all task config into database");
self.recording_rdb_num.fetch_add(1, Ordering::SeqCst);
for task in self.tasks.values() {
if unsafe { HasTaskConfigRecord(task.conf.common_data.task_id) } {
continue;
}
let state = task.status.lock().unwrap().state;
if state != State::Waiting && state != State::Paused {
continue;
}
let task_config = &task.conf;
let c_task_config =
task_config.to_c_struct(task.conf.common_data.task_id, task.conf.common_data.uid);
let ret = unsafe { RecordRequestTaskConfig(&c_task_config) };
info!("insert taskConfig DB ret is {}", ret);
}
self.recording_rdb_num.fetch_sub(1, Ordering::SeqCst);
}
fn restore_task(&mut self, task: Arc<RequestTask>) {
if task.conf.version == Version::API10 {
self.api10_background_task_count += 1;
}
let uid = task.conf.common_data.uid;
let task_id = task.conf.common_data.task_id;
if self.get_task(uid, task_id).is_some() {
return;
}
self.tasks.insert(task_id, task);
match self.app_task_map.get_mut(&uid) {
Some(set) => {
set.insert(task_id);
}
None => {
let mut set = HashSet::new();
set.insert(task_id);
self.app_task_map.insert(uid, set);
}
}
}
fn network_check_unload_sa(&self) -> bool {
let mut need_unload = false;
for task in self.tasks.values() {
let state = task.status.lock().unwrap().state;
if state == State::Completed
|| state == State::Failed
|| state == State::Removed
|| state == State::Stopped
|| ((state == State::Waiting || state == State::Paused)
&& (!task.is_satisfied_configuration() || unsafe { !IsOnline() }))
{
need_unload = true;
} else {
return false;
}
}
need_unload
}
pub(crate) fn query_all_task_config(&self) -> Option<Vec<TaskConfig>> {
debug!("query all task config in database");
let mut task_config_list: Vec<TaskConfig> = Vec::new();
let c_config_list_len = unsafe { QueryTaskConfigLen() };
if c_config_list_len <= 0 {
debug!("no task config in database");
return None;
}
let c_task_config_list = unsafe { QueryAllTaskConfig() };
if c_task_config_list.is_null() {
return None;
}
let c_task_config_ptrs =
unsafe { std::slice::from_raw_parts(c_task_config_list, c_config_list_len as usize) };
for c_task_config in c_task_config_ptrs.iter() {
let task_config = TaskConfig::from_c_struct(unsafe { &**c_task_config });
task_config_list.push(task_config);
unsafe { DeleteCTaskConfig(*c_task_config) };
}
unsafe { DeleteCTaskConfigs(c_task_config_list) };
Some(task_config_list)
}
}
extern "C" {
pub(crate) fn DeleteCTaskConfigs(ptr: *const *const CTaskConfig);
pub(crate) fn QueryAllTaskConfig() -> *const *const CTaskConfig;
pub(crate) fn QueryTaskConfigLen() -> i32;
pub(crate) fn DeleteCTaskConfig(ptr: *const CTaskConfig);
pub(crate) fn RecordRequestTaskConfig(taskConfig: *const CTaskConfig) -> bool;
pub(crate) fn CleanTaskConfigTable(taskId: u32, uid: u64) -> bool;
pub(crate) fn HasTaskConfigRecord(taskId: u32) -> bool;
}

View File

@ -0,0 +1,120 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// limitations under the License.
//! Request ability services implementations.
use std::hint;
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicU8, Ordering};
use crate::manager::task_manager::TaskManagerEntry;
use crate::manager::TaskManager;
use crate::service::listener::{AppStateListener, NetworkChangeListener};
use crate::service::notify::{NotifyEntry, NotifyManager};
static mut REQUEST_ABILITY: MaybeUninit<RequestAbility> = MaybeUninit::uninit();
static STATE: AtomicU8 = AtomicU8::new(RequestAbility::NOT_INITED);
pub(crate) struct RequestAbility {
manager: TaskManagerEntry,
notify: NotifyEntry,
app: AppStateListener,
network: NetworkChangeListener,
}
impl RequestAbility {
const NOT_INITED: u8 = 0;
const INITIALIZING: u8 = 1;
const RUNNING: u8 = 2;
const STOPPING: u8 = 3;
const STOPPED: u8 = 4;
// `init` must have been called before calling `get_instance`.
pub(crate) fn get_instance() -> &'static Self {
loop {
match STATE.load(Ordering::SeqCst) {
Self::RUNNING | Self::STOPPED => return unsafe { &*REQUEST_ABILITY.as_ptr() },
_ => hint::spin_loop(),
}
}
}
pub(crate) fn init() {
if STATE
.compare_exchange(
Self::NOT_INITED,
Self::INITIALIZING,
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
unsafe {
REQUEST_ABILITY.write(Self {
manager: TaskManager::init(),
notify: NotifyManager::init(),
app: AppStateListener::init(),
network: NetworkChangeListener::init(),
});
RequestInitServiceHandler();
};
STATE.store(Self::RUNNING, Ordering::SeqCst);
}
}
pub(crate) fn stop() {
if STATE
.compare_exchange(
Self::RUNNING,
Self::STOPPING,
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
unsafe {
let ability = REQUEST_ABILITY.assume_init_ref();
// After entries shutdown, the `rx`s of these channels will be dropped.
ability.notify.shutdown();
ability.app.shutdown();
ability.network.shutdown();
};
STATE.store(Self::STOPPED, Ordering::SeqCst);
}
}
pub(crate) fn notify() -> NotifyEntry {
Self::get_instance().notify.clone()
}
pub(crate) fn task_manager() -> TaskManagerEntry {
Self::get_instance().manager.clone()
}
}
extern "C" {
pub(crate) fn RequestInitServiceHandler();
}

View File

@ -0,0 +1,250 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::HashMap;
use std::fs::File;
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::permission::PermissionChecker;
use crate::service::{get_calling_bundle, open_file_readonly, open_file_readwrite};
use crate::task::config::{Action, CommonTaskConfig, Network, TaskConfig, Version};
use crate::task::info::Mode;
use crate::utils::form_item::{FileSpec, FormItem};
use crate::utils::generate_task_id;
pub(crate) struct Construct;
impl Construct {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service construct");
if !PermissionChecker::check_internet() {
error!("Service construct: no INTERNET permission");
reply.write(&(ErrorCode::Permission as i32))?;
return Err(IpcStatusCode::Failed);
}
let action: u32 = data.read()?;
let action: Action = Action::from(action as u8);
let version: u32 = data.read()?;
let version: Version = Version::from(version as u8);
let mode: u32 = data.read()?;
let mode: Mode = Mode::from(mode as u8);
let cover: bool = data.read()?;
let network: u32 = data.read()?;
let network: Network = Network::from(network as u8);
let metered: bool = data.read()?;
let roaming: bool = data.read()?;
let retry: bool = data.read()?;
let redirect: bool = data.read()?;
let background: bool = data.read()?;
let index: u32 = data.read()?;
let begins: i64 = data.read()?;
let ends: i64 = data.read()?;
let gauge: bool = data.read()?;
let precise: bool = data.read()?;
let priority: u32 = data.read()?;
let url: String = data.read()?;
let title: String = data.read()?;
let method: String = data.read()?;
let token: String = data.read()?;
let description: String = data.read()?;
let data_base: String = data.read()?;
let bundle = get_calling_bundle();
// Creates task_id here, move it to task_manager later?
let task_id = generate_task_id();
let uid = get_calling_uid();
let mut form_items = Vec::new();
let form_size: u32 = data.read()?;
if form_size > data.get_readable_bytes() {
error!("Service construct: form_size too large");
reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
return Err(IpcStatusCode::Failed);
}
for _ in 0..form_size {
let name: String = data.read()?;
let value: String = data.read()?;
form_items.push(FormItem { name, value });
}
let mut files = Vec::<File>::new();
let mut file_specs: Vec<FileSpec> = Vec::new();
let file_size: u32 = data.read()?;
if file_size > data.get_readable_bytes() {
error!("Service construct: file_specs size too large");
reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
return Err(IpcStatusCode::Failed);
}
for _ in 0..file_size {
let name: String = data.read()?;
let path: String = data.read()?;
let file_name: String = data.read()?;
let mime_type: String = data.read()?;
if action == Action::UpLoad {
let file = open_file_readonly(uid, &bundle, &path)?;
files.push(file);
} else {
let file = open_file_readwrite(uid, &bundle, &path)?;
files.push(file);
}
let _fd_error: i32 = data.read()?;
file_specs.push(FileSpec {
name,
path,
file_name,
mime_type,
});
}
// Response bodies fd.
let body_file_size: u32 = data.read()?;
if body_file_size > data.get_readable_bytes() {
error!("Service construct: body_file size too large");
reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
return Err(IpcStatusCode::Failed);
}
let mut body_files = Vec::new();
let mut body_file_names: Vec<String> = Vec::new();
for _ in 0..body_file_size {
let file_name: String = data.read()?;
let body_file = open_file_readwrite(uid, &bundle, &file_name)?;
body_file_names.push(file_name);
body_files.push(body_file);
}
let header_size: u32 = data.read()?;
if header_size > data.get_readable_bytes() {
error!("Service construct: header size too large");
reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
return Err(IpcStatusCode::Failed);
}
let mut headers: HashMap<String, String> = HashMap::new();
for _ in 0..header_size {
let key: String = data.read()?;
let value: String = data.read()?;
headers.insert(key, value);
}
let extras_size: u32 = data.read()?;
if extras_size > data.get_readable_bytes() {
error!("Service construct: extras size too large");
reply.write(&(ErrorCode::IpcSizeTooLarge as i32))?;
return Err(IpcStatusCode::Failed);
}
let mut extras: HashMap<String, String> = HashMap::new();
for _ in 0..extras_size {
let key: String = data.read()?;
let value: String = data.read()?;
extras.insert(key, value);
}
let task_config = TaskConfig {
bundle,
url,
title,
description,
method,
headers,
data: data_base,
token,
extras,
version,
form_items,
file_specs,
body_file_names,
common_data: CommonTaskConfig {
task_id,
uid,
action,
mode,
cover,
network,
metered,
roaming,
retry,
redirect,
index,
begins: begins as u64,
ends,
gauge,
precise,
priority,
background,
},
};
debug!("Service construct: task_config constructed");
debug!("Service construct: target files {:?}", files);
let (event, rx) = EventMessage::construct(task_config, files, body_files);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
let ret = match rx.get() {
Some(ret) => ret,
None => {
error!("Service construct: receives ret failed");
return Err(IpcStatusCode::Failed);
}
};
debug!("Service construct: construct event sent to manager");
if version != Version::API10 {
let (event, _) = EventMessage::start(uid, task_id);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
debug!("Service construct: start event sent to manager");
}
reply.write(&(ret as i32))?;
if ret != ErrorCode::ErrOk {
error!("Service construct: construct task failed");
return Err(IpcStatusCode::Failed);
}
debug!("Service construct: task id {}", task_id);
reply.write(&(task_id as i32))?;
Ok(())
}
}

View File

@ -0,0 +1,143 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::io::Write;
use ipc_rust::{FileDesc, IpcStatusCode, String16};
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
const HELP_MSG: &str = "usage:\n\
-h help text for the tool\n\
-t [taskid] without taskid: display all task summary info; \
taskid: display one task detail info\n";
pub(crate) struct Dump;
impl Dump {
// Ignores all the file error.
pub(crate) fn execute(file: &FileDesc, args: &mut Vec<String16>) -> i32 {
info!("Service dump");
let len = args.len();
if len == 0 || args[0].get_string().eq("-h") {
let _ = file.as_ref().write(HELP_MSG.as_bytes());
return IpcStatusCode::Ok as i32;
}
if !args[0].get_string().eq("-t") {
let _ = file.as_ref().write("invalid args".as_bytes());
return IpcStatusCode::Ok as i32;
}
match len {
1 => dump_all_task_info(file),
2 => {
let task_id = args[1].get_string().parse::<u32>();
match task_id {
Ok(id) => dump_one_task_info(file, id),
Err(_) => {
let _ = file.as_ref().write("-t accept a number".as_bytes());
}
}
}
_ => {
let _ = file
.as_ref()
.write("too many args, -t accept no arg or one arg".as_bytes());
}
}
IpcStatusCode::Ok as i32
}
}
fn dump_all_task_info(file: &FileDesc) {
info!("Service dump: dump all task info");
let (event, rx) = EventMessage::dump_all();
if !RequestAbility::task_manager().send_event(event) {
return;
}
let infos = match rx.get() {
Some(infos) => infos,
None => {
error!("Service dump: receives infos failed");
return;
}
};
let len = infos.vec.len();
let mut file = file.as_ref();
let _ = file.write(format!("task num: {}\n", len).as_bytes());
if len > 0 {
let _ = file.write(
format!(
"{:<20}{:<12}{:<12}{:<12}\n",
"id", "action", "state", "reason"
)
.as_bytes(),
);
for info in infos.vec.iter() {
let _ = file.write(
format!(
"{:<20}{:<12}{:<12}{:<12}\n",
info.task_id, info.action as u8, info.state as u8, info.reason as u8
)
.as_bytes(),
);
}
}
}
fn dump_one_task_info(file: &FileDesc, task_id: u32) {
info!("Service dump: dump one task info");
let (event, rx) = EventMessage::dump_one(task_id);
if !RequestAbility::task_manager().send_event(event) {
return;
}
let task = match rx.get() {
Some(task) => task,
None => {
error!("Service dump: receives task failed");
return;
}
};
let mut file = file.as_ref();
if let Some(task) = task {
let _ = file.write(
format!(
"{:<20}{:<12}{:<12}{:<12}{:<12}{:<12}{}\n",
"id", "action", "state", "reason", "total_size", "tran_size", "url"
)
.as_bytes(),
);
let _ = file.write(
format!(
"{:<20}{:<12}{:<12}{:<12}{:<12}{:<12}{}\n",
task.task_id,
task.action as u8,
task.state as u8,
task.reason as u8,
task.total_size,
task.tran_size,
task.url
)
.as_bytes(),
);
} else {
let _ = file.write(format!("invalid task id {}", task_id).as_bytes());
}
}

View File

@ -0,0 +1,42 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
mod construct;
mod dump;
mod off;
mod on;
mod pause;
mod query;
mod query_mime_type;
mod remove;
mod resume;
mod search;
mod show;
mod start;
mod stop;
mod touch;
pub(crate) use construct::Construct;
pub(crate) use dump::Dump;
pub(crate) use off::Off;
pub(crate) use on::On;
pub(crate) use pause::Pause;
pub(crate) use query::Query;
pub(crate) use query_mime_type::QueryMimeType;
pub(crate) use remove::Remove;
pub(crate) use resume::Resume;
pub(crate) use search::Search;
pub(crate) use show::Show;
pub(crate) use start::Start;
pub(crate) use stop::Stop;
pub(crate) use touch::Touch;

View File

@ -0,0 +1,68 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::service::ability::RequestAbility;
use crate::service::notify::{Event, NotifyEvent};
pub(crate) struct Off;
impl Off {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service off");
let off_type: String = data.read()?;
debug!("Service off: off_type {:?}", off_type);
let event = match Event::try_from(off_type) {
Ok(event) => event,
Err(_) => {
error!("Service off: off_type not valid");
reply.write(&(ErrorCode::ParameterCheck as i32))?;
return Err(IpcStatusCode::Failed);
}
};
let id: String = data.read()?;
debug!("Service off: task_id {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service off: u32 task_id is {:?}", id);
let (event, rx) = NotifyEvent::off(event, id);
RequestAbility::notify().send_event(event);
let ret = match rx.get() {
Some(ret) => ret,
None => {
error!("Service off: receives ret failed");
return Err(IpcStatusCode::Failed);
}
};
reply.write(&(ret as i32))?;
if ret != ErrorCode::ErrOk {
error!("Service off: off failed for ret is {}", ret as i32);
return Err(IpcStatusCode::Failed);
}
Ok(())
}
_ => {
error!("Service off: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,69 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{BorrowedMsgParcel, IpcResult, IpcStatusCode, RemoteObj};
use crate::error::ErrorCode;
use crate::service::ability::RequestAbility;
use crate::service::notify::{Event, NotifyEvent};
pub(crate) struct On;
impl On {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service on");
let on_type: String = data.read()?;
debug!("Service on: on_type is {:?}", on_type);
let event = match Event::try_from(on_type) {
Ok(event) => event,
Err(_) => {
error!("Service on: on_type not valid");
reply.write(&(ErrorCode::ParameterCheck as i32))?;
return Err(IpcStatusCode::Failed);
}
};
let id: String = data.read()?;
debug!("Service on: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service on: u32 task_id is {}", id);
let obj: RemoteObj = data.read::<RemoteObj>()?;
let (event, rx) = NotifyEvent::on(event, id, obj);
RequestAbility::notify().send_event(event);
let ret = match rx.get() {
Some(ret) => ret,
None => {
error!("Service on: receives ret failed");
return Err(IpcStatusCode::Failed);
}
};
reply.write(&(ret as i32))?;
if ret != ErrorCode::ErrOk {
error!("Service on: on failed for ret is {}", ret as i32);
return Err(IpcStatusCode::Failed);
}
Ok(())
}
_ => {
error!("Service on: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,72 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::permission::PermissionChecker;
use crate::task::config::Version;
pub(crate) struct Pause;
impl Pause {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service pause");
let version: u32 = data.read()?;
debug!("Service pause: version {}", version);
if Version::from(version as u8) == Version::API9 && !PermissionChecker::check_internet() {
error!("Service pause: no INTERNET permission");
reply.write(&(ErrorCode::Permission as i32))?;
return Err(IpcStatusCode::Failed);
}
let id: String = data.read()?;
debug!("Service pause: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service pause: u32 task_id is {}", id);
let uid = get_calling_uid();
debug!("Service pause: uid is {}", uid);
let (event, rx) = EventMessage::pause(uid, id);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
let ret = match rx.get() {
Some(ret) => ret,
None => {
error!("Service pause: receives ret failed");
return Err(IpcStatusCode::Failed);
}
};
reply.write(&(ret as i32))?;
if ret != ErrorCode::ErrOk {
error!("Service pause: pause fail for ret is {}", ret as u32);
return Err(IpcStatusCode::Failed);
}
Ok(())
}
_ => {
error!("Service pause: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,82 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::permission::{PermissionChecker, QueryPermission};
use crate::service::{is_system_api, serialize_task_info};
use crate::task::config::Action;
pub(crate) struct Query;
impl Query {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service query");
if !is_system_api() {
error!("Service query: not system api");
reply.write(&(ErrorCode::SystemApi as i32))?;
return Err(IpcStatusCode::Failed);
}
let permission = PermissionChecker::check_query();
let action = match permission {
QueryPermission::NoPermission => {
error!("Service query: no QUERY permission");
reply.write(&(ErrorCode::Permission as i32))?;
return Err(IpcStatusCode::Failed);
}
QueryPermission::QueryDownLoad => Action::DownLoad,
QueryPermission::QueryUpload => Action::UpLoad,
QueryPermission::QueryAll => Action::Any,
};
let id: String = data.read()?;
debug!("Service query: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service query: u32 task_id is {}", id);
let (event, rx) = EventMessage::query(id, action);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
match rx.get() {
Some(Some(info)) => {
reply.write(&(ErrorCode::ErrOk as i32))?;
debug!("Service query: task_info - {:?}", info);
serialize_task_info(info, reply)?;
Ok(())
}
Some(None) => {
error!("Service query: task_id not found");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
None => {
error!("Service query: receives task_info failed");
Err(IpcStatusCode::Failed)
}
}
}
_ => {
error!("Service query: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,66 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::permission::PermissionChecker;
pub(crate) struct QueryMimeType;
impl QueryMimeType {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service query mime type");
if !PermissionChecker::check_internet() {
error!("Service query mime type: no INTERNET permission");
reply.write(&(ErrorCode::Permission as i32))?;
return Err(IpcStatusCode::Failed);
}
let id: String = data.read()?;
debug!("Service query mime type: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service query mime type: u32 task_id is {}", id);
let uid = get_calling_uid();
debug!("Service query mime type: uid is {}", uid);
let (event, rx) = EventMessage::query_mime_type(uid, id);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
let mime = match rx.get() {
Some(mime) => mime,
None => {
error!("Service query mime type: receives mime failed");
return Err(IpcStatusCode::Failed);
}
};
debug!("Service query mime type: {}", mime);
reply.write(&(ErrorCode::ErrOk as i32))?;
reply.write(&mime)?;
Ok(())
}
_ => {
error!("Service query mime type: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,69 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::permission::PermissionChecker;
use crate::task::config::Version;
pub(crate) struct Remove;
impl Remove {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service remove");
let version: u32 = data.read()?;
if Version::from(version as u8) == Version::API9 && !PermissionChecker::check_internet() {
error!("Service remove: no INTERNET permission");
reply.write(&(ErrorCode::Permission as i32))?;
return Err(IpcStatusCode::Failed);
}
let id: String = data.read()?;
debug!("Service remove: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service remove: u32 task_id is {}", id);
let uid = get_calling_uid();
debug!("Service remove: uid is {}", uid);
let (event, rx) = EventMessage::remove(uid, id);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
let ret = match rx.get() {
Some(ret) => ret,
None => {
error!("Service remove: receives ret failed");
return Err(IpcStatusCode::Failed);
}
};
reply.write(&(ret as i32))?;
if ret != ErrorCode::ErrOk {
error!("Service remove: remove failed for ret is {}", ret as i32);
return Err(IpcStatusCode::Failed);
}
Ok(())
}
_ => {
error!("Service remove: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::permission::PermissionChecker;
pub(crate) struct Resume;
impl Resume {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service resume");
if !PermissionChecker::check_internet() {
error!("Service resume: no INTERNET permission");
reply.write(&(ErrorCode::Permission as i32))?;
return Err(IpcStatusCode::Failed);
}
let id: String = data.read()?;
debug!("Service resume: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service resume: u32 task_id is {}", id);
let uid = get_calling_uid();
debug!("Service resume: uid is {}", uid);
let (event, rx) = EventMessage::resume(uid, id);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
let ret = match rx.get() {
Some(ret) => ret,
None => {
error!("Service resume: receives ret failed");
return Err(IpcStatusCode::Failed);
}
};
reply.write(&(ret as i32))?;
if ret != ErrorCode::ErrOk {
error!("Service resume: resume failed for ret is {}", ret as i32);
return Err(IpcStatusCode::Failed);
}
Ok(())
}
_ => {
error!("Service resume: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,75 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::{get_calling_bundle, is_system_api};
use crate::utils::filter::{CommonFilter, Filter};
pub(crate) struct Search;
impl Search {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service search");
let mut bundle: String = data.read()?;
if !is_system_api() {
debug!("Service search: not system api");
bundle = get_calling_bundle();
debug!("Service search: bundle change: {}", bundle);
}
debug!("Service search: bundle is {}", bundle);
let before: i64 = data.read()?;
debug!("Service search: before is {}", before);
let after: i64 = data.read()?;
debug!("Service search: after is {}", after);
let state: u32 = data.read()?;
debug!("Service search: state is {}", state);
let action: u32 = data.read()?;
debug!("Service search: action is {}", action);
let mode: u32 = data.read()?;
debug!("Service search: mode is {}", mode);
let common_data = CommonFilter {
before,
after,
state: state as u8,
action: action as u8,
mode: mode as u8,
};
let filter = Filter {
bundle,
common_data,
};
let (event, rx) = EventMessage::search(filter);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
let ids = match rx.get() {
Some(ids) => ids,
None => {
error!("Service search: receives ids failed");
return Err(IpcStatusCode::Failed);
}
};
debug!("Service search: search task ids is {:?}", ids);
reply.write(&(ids.len() as u32))?;
for it in ids.iter() {
reply.write(&(it.to_string()))?;
}
Ok(())
}
}

View File

@ -0,0 +1,72 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::permission::PermissionChecker;
use crate::service::serialize_task_info;
pub(crate) struct Show;
impl Show {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service show");
if !PermissionChecker::check_internet() {
error!("Service show: no INTERNET permission");
reply.write(&(ErrorCode::Permission as i32))?;
return Err(IpcStatusCode::Failed);
}
let id: String = data.read()?;
debug!("Service show: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service show: u32 task_id is {}", id);
let uid = get_calling_uid();
debug!("Service show: uid is {}", uid);
let (event, rx) = EventMessage::show(uid, id);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
match rx.get() {
Some(Some(info)) => {
reply.write(&(ErrorCode::ErrOk as i32))?;
debug!("Service show: task_info {:?}", info);
serialize_task_info(info, reply)?;
Ok(())
}
Some(None) => {
error!("Service show: task_id not found");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
None => {
error!("Service show: receives task_info failed");
Err(IpcStatusCode::Failed)
}
}
}
_ => {
error!("Service show: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,68 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::permission::PermissionChecker;
pub(crate) struct Start;
impl Start {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
info!("Service start");
if !PermissionChecker::check_internet() {
error!("Service start: no INTERNET permission.");
reply.write(&(ErrorCode::Permission as i32))?;
return Err(IpcStatusCode::Failed);
}
let id: String = data.read()?;
debug!("Service start: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service start: u32 task_id is {}", id);
let uid = get_calling_uid();
debug!("Service start: uid is {}", uid);
let (event, rx) = EventMessage::start(uid, id);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
let ret = match rx.get() {
Some(ret) => ret,
None => {
error!("Service start: receives ret failed");
return Err(IpcStatusCode::Failed);
}
};
reply.write(&(ret as i32))?;
if ret != ErrorCode::ErrOk {
error!("Service start: start failed for ret is {}", ret as i32);
return Err(IpcStatusCode::Failed);
}
Ok(())
}
_ => {
error!("Service start: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,60 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
pub(crate) struct Stop;
impl Stop {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
debug!("Service stop");
let id: String = data.read()?;
debug!("Service stop: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service stop: u32 task_id is {}", id);
let uid = get_calling_uid();
debug!("Service stop: uid is {}", uid);
let (event, rx) = EventMessage::stop(uid, id);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
let ret = match rx.get() {
Some(ret) => ret,
None => {
error!("Service stop: receives ret failed");
return Err(IpcStatusCode::Failed);
}
};
reply.write(&(ret as i32))?;
if ret != ErrorCode::ErrOk {
error!("Service stop: stop failed for ret is {}", ret as i32);
return Err(IpcStatusCode::Failed);
}
Ok(())
}
_ => {
error!("Service stop: task_id not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::{get_calling_uid, BorrowedMsgParcel, IpcResult, IpcStatusCode};
use crate::error::ErrorCode;
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::service::serialize_task_info;
pub(crate) struct Touch;
impl Touch {
pub(crate) fn execute(
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
debug!("Service touch");
let id: String = data.read()?;
debug!("Service touch: task_id is {}", id);
match id.parse::<u32>() {
Ok(id) => {
debug!("Service touch: u32 task_id is {}", id);
let token: String = data.read()?;
debug!("Service touch: token is {}", token);
let uid = get_calling_uid();
debug!("Service touch: uid is {}", uid);
let (event, rx) = EventMessage::touch(uid, id, token);
if !RequestAbility::task_manager().send_event(event) {
return Err(IpcStatusCode::Failed);
}
match rx.get() {
Some(Some(info)) => {
reply.write(&(ErrorCode::ErrOk as i32))?;
debug!("Service touch: task_info get");
serialize_task_info(info, reply)?;
Ok(())
}
Some(None) => {
error!("Service touch: task_id or token not found");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
None => {
error!("Service touch: receives task_info failed");
Err(IpcStatusCode::Failed)
}
}
}
_ => {
error!("Service touch: task_id or token not valid");
reply.write(&(ErrorCode::TaskNotFound as i32))?;
Err(IpcStatusCode::Failed)
}
}
}
}

View File

@ -1,55 +1,53 @@
/*
* Copyright (C) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* SAID: 3706*/
/// Function code of RequestInterfaceCode
pub enum RequestInterfaceCode {
/// request construct & api10 create task
Construct = 0,
/// pause task
Pause,
/// query task || system api Queries specified task details
Query,
/// query mime type
QueryMimeType,
/// remove task || removes specifed task belongs to the caller
Remove,
/// resume task
Resume,
/// on task
On,
/// off task
Off,
/// ap10 start task
Start,
/// stop task
Stop,
/// Shows specified task details belongs to the caller
Show,
/// Touches specified task with token
Touch,
/// Searches tasks, for system
Search,
/// system api deletes specifed tasks
Clear,
}
/// Function code of RequestNotifyInterfaceCode
pub enum RequestNotifyInterfaceCode {
/// callback notification
Notify = 0,
/// Cache callback notification
DoneNotify,
}
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SAID: 3706
/// Function code of RequestInterfaceCode
pub(crate) enum RequestInterfaceCode {
/// request construct & api10 create task
Construct = 0,
/// pause task
Pause,
/// query task || system api Queries specified task details
Query,
/// query mime type
QueryMimeType,
/// remove task || removes specifed task belongs to the caller
Remove,
/// resume task
Resume,
/// on task
On,
/// off task
Off,
/// ap10 start task
Start,
/// stop task
Stop,
/// Shows specified task details belongs to the caller
Show,
/// Touches specified task with token
Touch,
/// Searches tasks, for system
Search,
/// system api deletes specifed tasks
Clear,
}
/// Function code of RequestNotifyInterfaceCode
pub(crate) enum RequestNotifyInterfaceCode {
/// callback notification
Notify = 0,
/// Cache callback notification
DoneNotify,
}

View File

@ -0,0 +1,51 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
use crate::task::info::ApplicationState;
pub(crate) struct AppStateListener;
impl AppStateListener {
pub(crate) fn init() -> Self {
info!("AppStateListener prepares to be inited");
unsafe {
RegisterAPPStateCallback(app_state_change_callback);
}
info!("AppStateListener is inited");
Self
}
pub(crate) fn shutdown(&self) {
// Considers remove the callback.
info!("AppStateListener is stopped");
}
}
extern "C" fn app_state_change_callback(uid: i32, state: i32) {
info!("Receives app state change callback");
let state = match state {
2 => ApplicationState::Foreground,
4 => ApplicationState::Background,
5 => ApplicationState::Terminated,
_ => return,
};
RequestAbility::task_manager().send_event(EventMessage::app_state_change(uid as u64, state));
}
extern "C" {
fn RegisterAPPStateCallback(f: extern "C" fn(i32, i32));
}

View File

@ -0,0 +1,18 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
mod app;
mod network;
pub(crate) use app::AppStateListener;
pub(crate) use network::NetworkChangeListener;

View File

@ -0,0 +1,42 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::manager::events::EventMessage;
use crate::service::ability::RequestAbility;
pub(crate) struct NetworkChangeListener;
impl NetworkChangeListener {
pub(crate) fn init() -> Self {
info!("NetworkChangeListener prepares to be inited");
unsafe {
RegisterNetworkCallback(network_change_callback);
}
info!("NetworkChangeListener is inited");
Self
}
pub(crate) fn shutdown(&self) {
// Considers remove the callback.
info!("NetworkChangeListener is stopped");
}
}
extern "C" fn network_change_callback() {
info!("Receives network change callback");
RequestAbility::task_manager().send_event(EventMessage::network_change());
}
extern "C" {
fn RegisterNetworkCallback(f: extern "C" fn());
}

View File

@ -0,0 +1,362 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! This crate implement the request server service.
pub(crate) mod ability;
pub(crate) mod command;
#[allow(unused)]
pub(crate) mod interface;
pub(crate) mod listener;
pub(crate) mod notify;
pub(crate) mod permission;
use std::fs::{File, OpenOptions};
pub(crate) use interface::{RequestInterfaceCode, RequestNotifyInterfaceCode};
use ipc_rust::{
define_remote_object, get_calling_token_id, BorrowedMsgParcel, FileDesc, IRemoteBroker,
InterfaceToken, IpcResult, IpcStatusCode, RemoteObj, RemoteStub, String16,
};
use crate::task::info::TaskInfo;
use crate::utils::c_wrapper::CStringWrapper;
define_remote_object!(
RequestServiceInterface["ohos.request.service"] {
stub: RequestServiceStub(on_remote_request),
proxy: RequestServiceProxy,
}
);
fn on_remote_request(
stub: &dyn RequestServiceInterface,
code: u32,
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
const SERVICE_TOKEN: &str = "OHOS.Download.RequestServiceInterface";
info!("Processes on_remote_request, code: {}", code);
match data.read::<InterfaceToken>().map(|token| token.get_token()) {
Ok(token) if token == SERVICE_TOKEN => {}
_ => {
error!("Gets invalid token");
return Err(IpcStatusCode::Failed);
}
};
match code.try_into()? {
RequestInterfaceCode::Construct => stub.construct(data, reply),
RequestInterfaceCode::Pause => stub.pause(data, reply),
RequestInterfaceCode::Query => stub.query(data, reply),
RequestInterfaceCode::QueryMimeType => stub.query_mime_type(data, reply),
RequestInterfaceCode::Remove => stub.remove(data, reply),
RequestInterfaceCode::Resume => stub.resume(data, reply),
RequestInterfaceCode::On => stub.on(data, reply),
RequestInterfaceCode::Off => stub.off(data, reply),
RequestInterfaceCode::Start => stub.start(data, reply),
RequestInterfaceCode::Stop => stub.stop(data, reply),
RequestInterfaceCode::Show => stub.show(data, reply),
RequestInterfaceCode::Touch => stub.touch(data, reply),
RequestInterfaceCode::Search => stub.search(data, reply),
RequestInterfaceCode::Clear => Ok(()),
}
}
impl TryFrom<u32> for RequestInterfaceCode {
type Error = IpcStatusCode;
fn try_from(code: u32) -> IpcResult<Self> {
match code {
_ if code == Self::Construct as u32 => Ok(Self::Construct),
_ if code == Self::Pause as u32 => Ok(Self::Pause),
_ if code == Self::Query as u32 => Ok(Self::Query),
_ if code == Self::QueryMimeType as u32 => Ok(Self::QueryMimeType),
_ if code == Self::Remove as u32 => Ok(Self::Remove),
_ if code == Self::Resume as u32 => Ok(Self::Resume),
_ if code == Self::On as u32 => Ok(Self::On),
_ if code == Self::Off as u32 => Ok(Self::Off),
_ if code == Self::Start as u32 => Ok(Self::Start),
_ if code == Self::Stop as u32 => Ok(Self::Stop),
_ if code == Self::Show as u32 => Ok(Self::Show),
_ if code == Self::Touch as u32 => Ok(Self::Touch),
_ if code == Self::Search as u32 => Ok(Self::Search),
_ if code == Self::Clear as u32 => Ok(Self::Clear),
_ => Err(IpcStatusCode::Failed),
}
}
}
/// Functions between proxy and stub.
pub trait RequestServiceInterface: IRemoteBroker {
/// Constructs or creates a task.
fn construct(
&self,
_data: &BorrowedMsgParcel,
_reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
Ok(())
}
/// Pauses a task.
fn pause(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Queries tasks.
fn query(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Queries the mime type of a task.
fn query_mime_type(
&self,
_data: &BorrowedMsgParcel,
_reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
Ok(())
}
/// Removes a task.
fn remove(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Resumes a task.
fn resume(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Sets the `on` callback of a task.
fn on(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Sets the `off` callback of a task.
fn off(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Starts a task.
fn start(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Stops a task.
fn stop(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Shows a specified task details which belongs to the caller.
fn show(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Touches a specified task with token.
fn touch(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
/// Searches tasks of this system.
fn search(&self, _data: &BorrowedMsgParcel, _reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
Ok(())
}
}
impl RequestServiceInterface for RequestServiceProxy {}
/// RequestService type
pub struct RequestService;
impl IRemoteBroker for RequestService {
fn dump(&self, file: &FileDesc, args: &mut Vec<String16>) -> i32 {
command::Dump::execute(file, args)
}
}
impl RequestServiceInterface for RequestService {
fn construct(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Construct::execute(data, reply)
}
fn pause(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Pause::execute(data, reply)
}
fn query(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Query::execute(data, reply)
}
fn query_mime_type(
&self,
data: &BorrowedMsgParcel,
reply: &mut BorrowedMsgParcel,
) -> IpcResult<()> {
command::QueryMimeType::execute(data, reply)
}
fn remove(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Remove::execute(data, reply)
}
fn resume(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Resume::execute(data, reply)
}
fn on(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::On::execute(data, reply)
}
fn off(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Off::execute(data, reply)
}
fn start(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Start::execute(data, reply)
}
fn stop(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Stop::execute(data, reply)
}
fn show(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Show::execute(data, reply)
}
fn touch(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Touch::execute(data, reply)
}
fn search(&self, data: &BorrowedMsgParcel, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
command::Search::execute(data, reply)
}
}
pub(crate) fn serialize_task_info(tf: TaskInfo, reply: &mut BorrowedMsgParcel) -> IpcResult<()> {
reply.write(&(tf.common_data.gauge))?;
reply.write(&(tf.common_data.retry))?;
reply.write(&(tf.common_data.action as u32))?;
reply.write(&(tf.common_data.mode as u32))?;
reply.write(&(tf.common_data.reason as u32))?;
reply.write(&(tf.common_data.tries))?;
reply.write(&(tf.common_data.uid.to_string()))?;
reply.write(&(tf.bundle))?;
reply.write(&(tf.url))?;
reply.write(&(tf.common_data.task_id.to_string()))?;
reply.write(&tf.title)?;
reply.write(&tf.mime_type)?;
reply.write(&(tf.common_data.ctime))?;
reply.write(&(tf.common_data.mtime))?;
reply.write(&(tf.data))?;
reply.write(&(tf.description))?;
reply.write(&(tf.common_data.priority))?;
reply.write(&(tf.form_items.len() as u32))?;
for i in 0..tf.form_items.len() {
reply.write(&(tf.form_items[i].name))?;
reply.write(&(tf.form_items[i].value))?;
}
reply.write(&(tf.file_specs.len() as u32))?;
for i in 0..tf.file_specs.len() {
reply.write(&(tf.file_specs[i].name))?;
reply.write(&(tf.file_specs[i].path))?;
reply.write(&(tf.file_specs[i].file_name))?;
reply.write(&(tf.file_specs[i].mime_type))?;
}
reply.write(&(tf.progress.common_data.state as u32))?;
let index = tf.progress.common_data.index;
reply.write(&(index as u32))?;
reply.write(&(tf.progress.processed[index] as u64))?;
reply.write(&(tf.progress.common_data.total_processed as u64))?;
reply.write(&(tf.progress.sizes))?;
reply.write(&(tf.progress.extras.len() as u32))?;
for (k, v) in tf.progress.extras.iter() {
reply.write(&(k))?;
reply.write(&(v))?;
}
reply.write(&(tf.extras.len() as u32))?;
for (k, v) in tf.extras.iter() {
reply.write(&(k))?;
reply.write(&(v))?;
}
reply.write(&(tf.common_data.version as u32))?;
reply.write(&(tf.each_file_status.len() as u32))?;
for item in tf.each_file_status.iter() {
reply.write(&(item.path))?;
reply.write(&(item.reason as u32))?;
reply.write(&(item.message))?;
}
Ok(())
}
pub(crate) fn get_calling_bundle() -> String {
debug!("Gets calling bundle");
let token_id = get_calling_token_id();
debug!("Gets token id {}", &token_id);
unsafe { GetCallingBundle(token_id).to_string() }
}
pub(crate) fn is_system_api() -> bool {
debug!("Checks if the api is a system_api");
let token_id = get_calling_token_id();
debug!("Gets token id {}", &token_id);
unsafe { RequestIsSystemAPI(token_id) }
}
pub(crate) fn open_file_readwrite(uid: u64, bundle: &str, path: &str) -> IpcResult<File> {
match OpenOptions::new()
.read(true)
.write(true)
.append(true)
.open(convert_path(uid, bundle, path))
{
Ok(file) => Ok(file),
Err(e) => {
error!("open_file_readwrite failed, err is {:?}", e);
Err(IpcStatusCode::Failed)
}
}
}
pub(crate) fn open_file_readonly(uid: u64, bundle: &str, path: &str) -> IpcResult<File> {
match OpenOptions::new()
.read(true)
.open(convert_path(uid, bundle, path))
{
Ok(file) => Ok(file),
Err(e) => {
error!("open_file_readonly failed, err is {:?}", e);
Err(IpcStatusCode::Failed)
}
}
}
fn convert_path(uid: u64, bundle: &str, path: &str) -> String {
let uuid = uid / 200000;
let base = "/data/storage/el2/base/";
format!(
"/data/app/el2/{}/base/{}/{}",
uuid,
bundle,
path.replace(base, "")
)
}
extern "C" {
pub(crate) fn GetCallingBundle(token_id: u64) -> CStringWrapper;
pub(crate) fn RequestIsSystemAPI(token_id: u64) -> bool;
}

View File

@ -0,0 +1,242 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::HashMap;
use ipc_rust::{IRemoteObj, InterfaceToken, IpcResult, MsgParcel, RemoteObj};
use ylong_runtime::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
use ylong_runtime::sync::oneshot::Sender;
use crate::error::ErrorCode;
use crate::service::notify::{Event, NotifyData, NotifyEvent};
use crate::service::RequestNotifyInterfaceCode;
use crate::task::info::State;
pub(crate) struct NotifyManager {
rx: UnboundedReceiver<NotifyEvent>,
remotes: HashMap<NotifyKey, Notifier>,
unregistered: HashMap<NotifyKey, Box<NotifyData>>,
}
impl NotifyManager {
fn new(rx: UnboundedReceiver<NotifyEvent>) -> Self {
Self {
rx,
remotes: HashMap::new(),
unregistered: HashMap::new(),
}
}
pub(crate) fn init() -> NotifyEntry {
info!("NotifyManager prepare to be inited");
let (tx, rx) = unbounded_channel::<NotifyEvent>();
ylong_runtime::spawn(Self::new(rx).run());
let entry = NotifyEntry::new(tx);
info!("NotifyManager is inited");
entry
}
pub(crate) async fn run(mut self) {
loop {
let event = match self.rx.recv().await {
Ok(message) => message,
Err(e) => {
error!("Notifier recv error {:?}", e);
continue;
}
};
match event {
NotifyEvent::Notify(event, data) => self.notify(event, data),
NotifyEvent::On(event, id, obj, tx) => self.on(event, id, obj, tx),
NotifyEvent::Off(event, id, sender) => self.off(event, id, sender),
NotifyEvent::Clear(id) => self.clear(id),
NotifyEvent::Shutdown => {
info!("NotifyManager shuts down");
return;
}
}
}
}
}
impl NotifyManager {
fn notify(&mut self, event: Event, data: Box<NotifyData>) {
debug!("NotifyManager gets event: {}", event.as_str());
let key = NotifyKey::new(event, data.task_id);
if let Some(notifier) = self.remotes.get(&key) {
debug!("NotifyManager finds key succeed: {:?}", key);
// Ignores notify failed.
notifier.notify(event, data);
} else {
debug!("NotifyManager finds key failed: {:?}", key);
self.unregistered.insert(key, data);
}
}
fn on(&mut self, event: Event, id: u32, obj: RemoteObj, sender: Sender<ErrorCode>) {
let key = NotifyKey::new(event, id);
let notifier = Notifier::new(obj);
if let Some(data) = self.unregistered.remove(&key) {
debug!("NotifyManager notifies unregistered key: {:?}", key);
notifier.notify(event, data);
self.unregistered.remove(&key);
}
self.remotes.insert(key, notifier);
debug!("NotifyManager has inserted key: {:?}", key);
let _ = sender.send(ErrorCode::ErrOk);
}
fn off(&mut self, event: Event, id: u32, sender: Sender<ErrorCode>) {
let key = NotifyKey::new(event, id);
if self.remotes.remove(&key).is_some() {
debug!("NotifyManager removes key: {:?}", key);
// Sends error code immediately, ignore the result.
let _ = sender.send(ErrorCode::ErrOk);
} else {
error!("NotifyManager removes key failed: {:?}", key);
// Sends error code immediately, ignore the result.
let _ = sender.send(ErrorCode::Other);
}
}
fn clear(&mut self, id: u32) {
let events = [
Event::Complete,
Event::Fail,
Event::HeaderReceive,
Event::Pause,
Event::Progress,
Event::Remove,
Event::Resume,
];
// Clears objects and unregistered notify data of the target task.
for event in events {
let key = NotifyKey::new(event, id);
self.remotes.remove(&key);
self.unregistered.remove(&key);
}
debug!("NotifyManager has cleared all the key of Task: {:?}", id);
}
}
#[derive(Clone)]
pub(crate) struct NotifyEntry {
tx: UnboundedSender<NotifyEvent>,
}
impl NotifyEntry {
fn new(tx: UnboundedSender<NotifyEvent>) -> Self {
Self { tx }
}
pub(crate) fn shutdown(&self) {
// Ignore the result.
self.send_event(NotifyEvent::shutdown());
}
pub(crate) fn send_event(&self, event: NotifyEvent) {
if self.tx.send(event).is_err() {
error!("Sends NotifyEvent failed");
}
}
}
#[derive(Clone)]
struct Notifier {
obj: RemoteObj,
}
impl Notifier {
fn new(obj: RemoteObj) -> Self {
Self { obj }
}
fn notify(&self, event: Event, data: Box<NotifyData>) {
debug!("Notifier gets notify data: {:?}", data);
if data.progress.common_data.index >= data.progress.sizes.len() {
error!("During notify: index out of range");
return;
}
let common_data = &data.progress.common_data;
if (common_data.state == State::Running as u8 || common_data.state == State::Retrying as u8)
&& common_data.total_processed == 0
{
return;
}
let mut parcel = match MsgParcel::new() {
Some(parcel) => parcel,
None => {
error!("During notify: create MsgParcel failed");
return;
}
};
if write_parcel(&mut parcel, event, data.as_ref()).is_err() {
error!("During notify: ipc write failed");
return;
}
debug!("During notify: send request");
if self
.obj
.send_request(RequestNotifyInterfaceCode::Notify as u32, &parcel, false)
.is_err()
{
error!("During notify: send request failed");
}
}
}
fn write_parcel(parcel: &mut MsgParcel, event: Event, data: &NotifyData) -> IpcResult<()> {
parcel.write(&InterfaceToken::new("OHOS.Download.NotifyInterface"))?;
parcel.write(&(event.as_str()))?;
parcel.write(&(data.task_id.to_string()))?;
parcel.write(&(data.progress.common_data.state as u32))?;
let index = data.progress.common_data.index;
parcel.write(&(index as u32))?;
parcel.write(&(data.progress.processed[index] as u64))?;
parcel.write(&(data.progress.common_data.total_processed as u64))?;
parcel.write(&(data.progress.sizes))?;
parcel.write(&(data.progress.extras.len() as u32))?;
for (k, v) in data.progress.extras.iter() {
parcel.write(&k)?;
parcel.write(&v)?;
}
parcel.write(&(data.action as u32))?;
parcel.write(&(data.version as u32))?;
parcel.write(&(data.each_file_status.len() as u32))?;
for status in data.each_file_status.iter() {
parcel.write(&(status.path))?;
parcel.write(&(status.reason as u32))?;
parcel.write(&(status.message))?;
}
Ok(())
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct NotifyKey {
event: Event,
task_id: u32,
}
impl NotifyKey {
fn new(event: Event, task_id: u32) -> Self {
Self { event, task_id }
}
}

View File

@ -0,0 +1,107 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
mod manager;
use ipc_rust::RemoteObj;
pub(crate) use manager::{NotifyEntry, NotifyManager};
use ylong_runtime::sync::oneshot::{channel, Sender};
use crate::error::ErrorCode;
use crate::task::notify::NotifyData;
use crate::utils::Recv;
pub(crate) enum NotifyEvent {
Notify(Event, Box<NotifyData>),
On(Event, u32, RemoteObj, Sender<ErrorCode>),
Off(Event, u32, Sender<ErrorCode>),
Clear(u32),
Shutdown,
}
impl NotifyEvent {
pub(crate) fn notify(event: Event, data: NotifyData) -> Self {
Self::Notify(event, Box::new(data))
}
pub(crate) fn on(event: Event, id: u32, obj: RemoteObj) -> (Self, Recv<ErrorCode>) {
let (tx, rx) = channel::<ErrorCode>();
(Self::On(event, id, obj, tx), Recv::new(rx))
}
pub(crate) fn off(event: Event, id: u32) -> (Self, Recv<ErrorCode>) {
let (tx, rx) = channel::<ErrorCode>();
(Self::Off(event, id, tx), Recv::new(rx))
}
pub(crate) fn clear(id: u32) -> Self {
Self::Clear(id)
}
pub(crate) fn shutdown() -> Self {
Self::Shutdown
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub(crate) enum Event {
Complete,
Fail,
HeaderReceive,
Pause,
Progress,
Remove,
Resume,
}
impl Event {
fn as_str(&self) -> &'static str {
match self {
Self::Complete => "complete",
Self::Fail => "fail",
Self::HeaderReceive => "headerReceive",
Self::Pause => "pause",
Self::Progress => "progress",
Self::Remove => "remove",
Self::Resume => "resume",
}
}
}
impl TryFrom<&str> for Event {
type Error = EventConvertError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"complete" => Ok(Self::Complete),
"fail" => Ok(Self::Fail),
"headerReceive" => Ok(Self::HeaderReceive),
"pause" => Ok(Self::Pause),
"progress" => Ok(Self::Progress),
"remove" => Ok(Self::Remove),
"resume" => Ok(Self::Resume),
_ => Err(EventConvertError),
}
}
}
impl TryFrom<String> for Event {
type Error = EventConvertError;
fn try_from(value: String) -> Result<Self, Self::Error> {
Event::try_from(value.as_str())
}
}
#[derive(Debug)]
pub(crate) struct EventConvertError;

View File

@ -0,0 +1,65 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use ipc_rust::get_calling_token_id;
use crate::utils::c_wrapper::CStringWrapper;
static INTERNET_PERMISSION: &str = "ohos.permission.INTERNET";
static QUERY_DOWNLOAD: &str = "ohos.permission.DOWNLOAD_SESSION_MANAGER";
static QUERY_UPLOAD: &str = "ohos.permission.UPLOAD_SESSION_MANAGER";
pub(crate) struct PermissionChecker;
impl PermissionChecker {
pub(crate) fn check_internet() -> bool {
debug!("Checks INTERNET permission");
unsafe {
RequestCheckPermission(
get_calling_token_id(),
CStringWrapper::from(INTERNET_PERMISSION),
)
}
}
pub(crate) fn check_query() -> QueryPermission {
debug!("Checks QUERY permission");
let id = get_calling_token_id();
let query_download =
unsafe { RequestCheckPermission(id, CStringWrapper::from(QUERY_DOWNLOAD)) };
let query_upload =
unsafe { RequestCheckPermission(id, CStringWrapper::from(QUERY_UPLOAD)) };
info!(
"Checks query_download permission is {}, query_upload permission is {}",
query_download, query_upload
);
match (query_download, query_upload) {
(true, true) => QueryPermission::QueryAll,
(true, false) => QueryPermission::QueryDownLoad,
(false, true) => QueryPermission::QueryUpload,
(false, false) => QueryPermission::NoPermission,
}
}
}
pub(crate) enum QueryPermission {
NoPermission = 0,
QueryDownLoad,
QueryUpload,
QueryAll,
}
extern "C" {
pub(crate) fn RequestCheckPermission(token_id: u64, permission: CStringWrapper) -> bool;
}

View File

@ -0,0 +1,65 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use hisysevent::{write, EventType, HiSysEventParam};
const DOMAIN: &str = "REQUEST";
pub(crate) const ERROR_INFO: &str = "ERROR_INFO";
pub(crate) const TASKS_TYPE: &str = "TASKS_TYPE";
pub(crate) const TOTAL_FILE_NUM: &str = "TOTAL_FILE_NUM";
pub(crate) const FAIL_FILE_NUM: &str = "FAIL_FILE_NUM";
pub(crate) const SUCCESS_FILE_NUM: &str = "SUCCESS_FILE_NUM";
/// System events structure which base on `Hisysevent`.
pub(crate) struct SysEvent<'a> {
event_kind: EventKind,
inner_type: EventType,
params: Vec<HiSysEventParam<'a>>,
}
impl<'a> SysEvent<'a> {
pub(crate) fn task_fault() -> Self {
Self {
event_kind: EventKind::TaskFault,
inner_type: EventType::Fault,
params: Vec::new(),
}
}
pub(crate) fn param(mut self, param: HiSysEventParam<'a>) -> Self {
self.params.push(param);
self
}
pub(crate) fn write(self) {
write(
DOMAIN,
self.event_kind.as_str(),
self.inner_type,
self.params.as_slice(),
);
}
}
enum EventKind {
TaskFault,
}
impl EventKind {
fn as_str(&self) -> &str {
match self {
EventKind::TaskFault => "TASK_FAULT",
}
}
}

View File

@ -0,0 +1,110 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::HashMap;
use super::info::Mode;
use crate::utils::form_item::{FileSpec, FormItem};
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u8)]
pub(crate) enum Action {
DownLoad = 0,
UpLoad,
Any,
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u8)]
pub(crate) enum Version {
API9 = 1,
API10,
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u8)]
pub(crate) enum Network {
Any = 0,
Wifi,
Cellular,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub(crate) struct CommonTaskConfig {
pub(crate) task_id: u32,
pub(crate) uid: u64,
pub(crate) action: Action,
pub(crate) mode: Mode,
pub(crate) cover: bool,
pub(crate) network: Network,
pub(crate) metered: bool,
pub(crate) roaming: bool,
pub(crate) retry: bool,
pub(crate) redirect: bool,
pub(crate) index: u32,
pub(crate) begins: u64,
pub(crate) ends: i64,
pub(crate) gauge: bool,
pub(crate) precise: bool,
pub(crate) priority: u32,
pub(crate) background: bool,
}
#[derive(Debug)]
pub(crate) struct TaskConfig {
pub(crate) bundle: String,
pub(crate) url: String,
pub(crate) title: String,
pub(crate) description: String,
pub(crate) method: String,
pub(crate) headers: HashMap<String, String>,
pub(crate) data: String,
pub(crate) token: String,
#[allow(unused)]
pub(crate) extras: HashMap<String, String>,
pub(crate) version: Version,
pub(crate) form_items: Vec<FormItem>,
pub(crate) file_specs: Vec<FileSpec>,
pub(crate) body_file_names: Vec<String>,
pub(crate) common_data: CommonTaskConfig,
}
impl From<u8> for Action {
fn from(value: u8) -> Self {
match value {
0 => Action::DownLoad,
1 => Action::UpLoad,
_ => Action::Any,
}
}
}
impl From<u8> for Version {
fn from(value: u8) -> Self {
match value {
2 => Version::API10,
_ => Version::API9,
}
}
}
impl From<u8> for Network {
fn from(value: u8) -> Self {
match value {
0 => Network::Any,
2 => Network::Cellular,
_ => Network::Wifi,
}
}
}

View File

@ -0,0 +1,173 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::pin::Pin;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::task::{Context, Poll};
use ylong_http_client::async_impl::{DownloadOperator, Downloader};
use ylong_http_client::{HttpClientError, Response, SpeedLimit, Timeout};
use super::operator::TaskOperator;
use super::reason::Reason;
use super::tick::Clock;
use crate::task::info::State;
use crate::task::RequestTask;
cfg_oh! {
use crate::trace::Trace;
}
const SECONDS_IN_ONE_WEEK: u64 = 7 * 24 * 60 * 60;
const LOW_SPEED_TIME: u64 = 60;
const LOW_SPEED_LIMIT: u64 = 1;
impl DownloadOperator for TaskOperator {
fn poll_download(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
data: &[u8],
) -> Poll<Result<usize, HttpClientError>> {
let me = self.get_mut();
if me.task.rate_limiting.load(Ordering::SeqCst) {
if me.check_point.take().is_none() {
Clock::get_instance().register(cx);
me.check_point = Some(());
return Poll::Pending;
}
} else {
Clock::get_instance().tick();
}
if me.task.range_request.load(Ordering::SeqCst) {
if me.task.range_response.load(Ordering::SeqCst) {
return me.poll_write_file(cx, data, 0);
}
// write partial response data
let begins = me.task.conf.common_data.begins;
let ends = me.task.conf.common_data.ends;
return me.poll_write_partial_file(cx, data, begins, ends);
}
me.poll_write_file(cx, data, 0)
}
fn poll_progress(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
_downloaded: u64,
_total: Option<u64>,
) -> Poll<Result<(), HttpClientError>> {
self.poll_progress_common(cx)
}
}
pub(crate) fn build_downloader(
task: Arc<RequestTask>,
response: Response,
) -> Downloader<TaskOperator> {
let task_operator = TaskOperator::new(task);
Downloader::builder()
.body(response)
.operator(task_operator)
.timeout(Timeout::from_secs(SECONDS_IN_ONE_WEEK))
.speed_limit(SpeedLimit::new().min_speed(LOW_SPEED_LIMIT, LOW_SPEED_TIME))
.build()
}
pub(crate) async fn download(task: Arc<RequestTask>) {
download_inner(task.clone()).await;
#[cfg(feature = "oh")]
use hisysevent::{build_number_param, build_str_param};
#[cfg(feature = "oh")]
use crate::sys_event::SysEvent;
#[cfg(feature = "oh")]
let reason = task.code.lock().unwrap()[0];
// If `Reason` is not `Default`a records this sys event.
#[cfg(feature = "oh")]
if reason != Reason::Default {
SysEvent::task_fault()
.param(build_str_param!(crate::sys_event::TASKS_TYPE, "DOWNLOAD"))
.param(build_number_param!(crate::sys_event::TOTAL_FILE_NUM, 1))
.param(build_number_param!(crate::sys_event::FAIL_FILE_NUM, 1))
.param(build_number_param!(crate::sys_event::SUCCESS_FILE_NUM, 0))
.param(build_number_param!(
crate::sys_event::ERROR_INFO,
reason as i32
))
.write();
}
}
async fn download_inner(task: Arc<RequestTask>) {
info!("begin download");
// Ensures `_trace` can only be freed when this function exits.
#[cfg(feature = "oh")]
Trace::start("download file");
let response = match task.client.as_ref() {
Some(client) => {
let request = match task.build_download_request().await {
Some(request) => request,
None => return,
};
let name = task.conf.file_specs[0].path.as_str();
let download = task.progress.lock().unwrap().processed[0];
// Ensures `_trace` can only be freed when this function exits.
#[cfg(feature = "oh")]
Trace::start(&format!(
"download file name: {name} downloaded size: {download}"
));
#[cfg(feature = "oh")]
Trace::finish();
client.request(request).await
}
None => {
return;
}
};
task.record_response_header(&response);
if !task.handle_response_error(&response).await {
error!("response error");
return;
}
let response = response.unwrap();
if !task.get_file_info(&response) {
return;
}
let mut downloader = build_downloader(task.clone(), response);
let result = downloader.download().await;
if !task.handle_download_error(&result) {
error!("handle_download_error");
return;
}
// Makes sure all the data has been written to the target file.
if let Some(file) = task.files.get(0) {
let _ = file.sync_all().await;
}
task.set_status(State::Completed, Reason::Default);
#[cfg(feature = "oh")]
Trace::finish();
}

View File

@ -0,0 +1,382 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::ffi::c_char;
use super::config::{Action, CommonTaskConfig, Network, TaskConfig, Version};
use super::info::{CommonTaskInfo, InfoSet, Mode, TaskInfo, UpdateInfo};
use super::notify::{CommonProgress, EachFileStatus, Progress};
use super::reason::Reason;
use crate::utils::c_wrapper::{
CFileSpec, CFormItem, CStringWrapper, DeleteCFileSpec, DeleteCFormItem, DeleteCStringPtr,
};
use crate::utils::form_item::{FileSpec, FormItem};
use crate::utils::{build_vec, hashmap_to_string, split_string, string_to_hashmap};
#[repr(C)]
pub(crate) struct CTaskConfig {
pub(crate) bundle: CStringWrapper,
pub(crate) url: CStringWrapper,
pub(crate) title: CStringWrapper,
pub(crate) description: CStringWrapper,
pub(crate) method: CStringWrapper,
pub(crate) headers: CStringWrapper,
pub(crate) data: CStringWrapper,
pub(crate) token: CStringWrapper,
pub(crate) extras: CStringWrapper,
pub(crate) version: u8,
pub(crate) form_items_ptr: *const CFormItem,
pub(crate) form_items_len: u32,
pub(crate) file_specs_ptr: *const CFileSpec,
pub(crate) file_specs_len: u32,
pub(crate) body_file_names_ptr: *const CStringWrapper,
pub(crate) body_file_names_len: u32,
pub(crate) common_data: CommonCTaskConfig,
}
#[repr(C)]
pub(crate) struct CommonCTaskConfig {
pub(crate) task_id: u32,
pub(crate) uid: u64,
pub(crate) action: u8,
pub(crate) mode: u8,
pub(crate) cover: bool,
pub(crate) network: u8,
pub(crate) metered: bool,
pub(crate) roaming: bool,
pub(crate) retry: bool,
pub(crate) redirect: bool,
pub(crate) index: u32,
pub(crate) begins: u64,
pub(crate) ends: i64,
pub(crate) gauge: bool,
pub(crate) precise: bool,
pub(crate) priority: u32,
pub(crate) background: bool,
}
#[repr(C)]
pub(crate) struct CEachFileStatus {
pub(crate) path: CStringWrapper,
pub(crate) reason: u8,
pub(crate) message: CStringWrapper,
}
impl EachFileStatus {
pub(crate) fn to_c_struct(&self) -> CEachFileStatus {
CEachFileStatus {
path: CStringWrapper::from(&self.path),
reason: self.reason as u8,
message: CStringWrapper::from(&self.message),
}
}
pub(crate) fn from_c_struct(c_struct: &CEachFileStatus) -> EachFileStatus {
EachFileStatus {
path: c_struct.path.to_string(),
reason: Reason::from(c_struct.reason),
message: c_struct.message.to_string(),
}
}
}
#[repr(C)]
pub(crate) struct CProgress {
pub(crate) common_data: CommonProgress,
pub(crate) sizes: CStringWrapper,
pub(crate) processed: CStringWrapper,
pub(crate) extras: CStringWrapper,
}
impl Progress {
pub(crate) fn to_c_struct(&self, sizes: &str, processed: &str, extras: &str) -> CProgress {
CProgress {
common_data: self.common_data.clone(),
sizes: CStringWrapper::from(sizes),
processed: CStringWrapper::from(processed),
extras: CStringWrapper::from(extras),
}
}
pub(crate) fn from_c_struct(c_struct: &CProgress) -> Self {
Progress {
common_data: c_struct.common_data.clone(),
sizes: split_string(&mut c_struct.sizes.to_string())
.map(|s| s.parse::<i64>().unwrap())
.collect(),
processed: split_string(&mut c_struct.processed.to_string())
.map(|s| s.parse::<usize>().unwrap())
.collect(),
extras: string_to_hashmap(&mut c_struct.extras.to_string()),
}
}
}
#[repr(C)]
pub(crate) struct CTaskInfo {
pub(crate) bundle: CStringWrapper,
pub(crate) url: CStringWrapper,
pub(crate) data: CStringWrapper,
pub(crate) token: CStringWrapper,
pub(crate) form_items_ptr: *const CFormItem,
pub(crate) form_items_len: u32,
pub(crate) file_specs_ptr: *const CFileSpec,
pub(crate) file_specs_len: u32,
pub(crate) title: CStringWrapper,
pub(crate) description: CStringWrapper,
pub(crate) mime_type: CStringWrapper,
pub(crate) progress: CProgress,
pub(crate) each_file_status_ptr: *const CEachFileStatus,
pub(crate) each_file_status_len: u32,
pub(crate) common_data: CommonTaskInfo,
}
impl TaskInfo {
pub(crate) fn to_c_struct(&self, info: &InfoSet) -> CTaskInfo {
CTaskInfo {
bundle: CStringWrapper::from(&self.bundle),
url: CStringWrapper::from(&self.url),
data: CStringWrapper::from(&self.data),
token: CStringWrapper::from(&self.token),
form_items_ptr: info.form_items.as_ptr(),
form_items_len: info.form_items.len() as u32,
file_specs_ptr: info.file_specs.as_ptr(),
file_specs_len: info.file_specs.len() as u32,
title: CStringWrapper::from(&self.title),
description: CStringWrapper::from(&self.description),
mime_type: CStringWrapper::from(&self.mime_type),
progress: self
.progress
.to_c_struct(&info.sizes, &info.processed, &info.extras),
each_file_status_ptr: info.each_file_status.as_ptr(),
each_file_status_len: info.each_file_status.len() as u32,
common_data: self.common_data,
}
}
pub(crate) fn from_c_struct(c_struct: &CTaskInfo) -> Self {
let progress = Progress::from_c_struct(&c_struct.progress);
let extras = progress.extras.clone();
// Removes this logic if api9 and api10 matched.
let mime_type = if c_struct.common_data.version == Version::API9 as u8 {
c_struct.mime_type.to_string()
} else {
String::new()
};
let task_info = TaskInfo {
bundle: c_struct.bundle.to_string(),
url: c_struct.url.to_string(),
data: c_struct.data.to_string(),
token: c_struct.token.to_string(),
form_items: build_vec(
c_struct.form_items_ptr,
c_struct.form_items_len as usize,
FormItem::from_c_struct,
),
file_specs: build_vec(
c_struct.file_specs_ptr,
c_struct.file_specs_len as usize,
FileSpec::from_c_struct,
),
title: c_struct.title.to_string(),
description: c_struct.description.to_string(),
mime_type,
progress,
extras,
each_file_status: build_vec(
c_struct.each_file_status_ptr,
c_struct.each_file_status_len as usize,
EachFileStatus::from_c_struct,
),
common_data: c_struct.common_data,
};
unsafe { DeleteCFormItem(c_struct.form_items_ptr) };
unsafe { DeleteCFileSpec(c_struct.file_specs_ptr) };
unsafe { DeleteCEachFileStatus(c_struct.each_file_status_ptr) };
task_info
}
}
#[repr(C)]
pub(crate) struct CUpdateInfo {
pub(crate) mtime: u64,
pub(crate) reason: u8,
pub(crate) tries: u32,
pub(crate) mime_type: CStringWrapper,
pub(crate) progress: CProgress,
pub(crate) each_file_status_ptr: *const CEachFileStatus,
pub(crate) each_file_status_len: u32,
}
impl UpdateInfo {
pub(crate) fn to_c_struct(
&self,
sizes: &str,
processed: &str,
extras: &str,
each_file_status: &Vec<CEachFileStatus>,
) -> CUpdateInfo {
CUpdateInfo {
mtime: self.mtime,
reason: self.reason,
tries: self.tries,
mime_type: CStringWrapper::from(self.mime_type.as_str()),
progress: self.progress.to_c_struct(sizes, processed, extras),
each_file_status_ptr: each_file_status.as_ptr(),
each_file_status_len: each_file_status.len() as u32,
}
}
}
#[repr(C)]
pub(crate) struct RequestTaskMsg {
pub(crate) task_id: u32,
pub(crate) uid: i32,
pub(crate) action: u8,
}
#[derive(Debug)]
#[repr(C)]
pub(crate) struct NetworkInfo {
pub(crate) network_type: Network,
pub(crate) is_metered: bool,
pub(crate) is_roaming: bool,
}
impl TaskConfig {
pub(crate) fn to_c_struct(&self, task_id: u32, uid: u64) -> CTaskConfig {
let form_items: Vec<CFormItem> = self.form_items.iter().map(|x| x.to_c_struct()).collect();
let file_specs: Vec<CFileSpec> = self.file_specs.iter().map(|x| x.to_c_struct()).collect();
let body_file_names: Vec<CStringWrapper> = self
.body_file_names
.iter()
.map(CStringWrapper::from)
.collect();
CTaskConfig {
bundle: CStringWrapper::from(&self.bundle),
url: CStringWrapper::from(&self.url),
title: CStringWrapper::from(&self.title),
description: CStringWrapper::from(&self.description),
method: CStringWrapper::from(&self.method),
headers: CStringWrapper::from(&hashmap_to_string(&self.headers)),
data: CStringWrapper::from(&self.data),
token: CStringWrapper::from(&self.token),
extras: CStringWrapper::from(&hashmap_to_string(&self.extras)),
version: self.version as u8,
form_items_ptr: form_items.as_ptr(),
form_items_len: form_items.len() as u32,
file_specs_ptr: file_specs.as_ptr(),
file_specs_len: file_specs.len() as u32,
body_file_names_ptr: body_file_names.as_ptr() as *const CStringWrapper,
body_file_names_len: body_file_names.len() as u32,
common_data: CommonCTaskConfig {
task_id,
uid,
action: self.common_data.action as u8,
mode: self.common_data.mode as u8,
cover: self.common_data.cover,
network: self.common_data.network as u8,
metered: self.common_data.metered,
roaming: self.common_data.roaming,
retry: self.common_data.retry,
redirect: self.common_data.redirect,
index: self.common_data.index,
begins: self.common_data.begins,
ends: self.common_data.ends,
gauge: self.common_data.gauge,
precise: self.common_data.precise,
priority: self.common_data.priority,
background: self.common_data.background,
},
}
}
pub(crate) fn from_c_struct(c_struct: &CTaskConfig) -> Self {
let task_config = TaskConfig {
bundle: c_struct.bundle.to_string(),
url: c_struct.url.to_string(),
title: c_struct.title.to_string(),
description: c_struct.description.to_string(),
method: c_struct.method.to_string(),
headers: string_to_hashmap(&mut c_struct.headers.to_string()),
data: c_struct.data.to_string(),
token: c_struct.token.to_string(),
extras: string_to_hashmap(&mut c_struct.extras.to_string()),
version: Version::from(c_struct.version),
form_items: build_vec(
c_struct.form_items_ptr,
c_struct.form_items_len as usize,
FormItem::from_c_struct,
),
file_specs: build_vec(
c_struct.file_specs_ptr,
c_struct.file_specs_len as usize,
FileSpec::from_c_struct,
),
body_file_names: build_vec(
c_struct.body_file_names_ptr,
c_struct.body_file_names_len as usize,
CStringWrapper::to_string,
),
common_data: CommonTaskConfig {
task_id: c_struct.common_data.task_id,
uid: c_struct.common_data.uid,
action: Action::from(c_struct.common_data.action),
mode: Mode::from(c_struct.common_data.mode),
cover: c_struct.common_data.cover,
network: Network::from(c_struct.common_data.network),
metered: c_struct.common_data.metered,
roaming: c_struct.common_data.roaming,
retry: c_struct.common_data.retry,
redirect: c_struct.common_data.redirect,
index: c_struct.common_data.index,
begins: c_struct.common_data.begins,
ends: c_struct.common_data.ends,
gauge: c_struct.common_data.gauge,
precise: c_struct.common_data.precise,
priority: c_struct.common_data.priority,
background: c_struct.common_data.background,
},
};
unsafe { DeleteCFormItem(c_struct.form_items_ptr) };
unsafe { DeleteCFileSpec(c_struct.file_specs_ptr) };
unsafe { DeleteCStringPtr(c_struct.body_file_names_ptr) };
task_config
}
}
extern "C" {
pub(crate) fn GetNetworkInfo() -> *const NetworkInfo;
pub(crate) fn DeleteCTaskInfo(ptr: *const CTaskInfo);
pub(crate) fn RecordRequestTaskInfo(taskInfo: *const CTaskInfo) -> bool;
pub(crate) fn DeleteCEachFileStatus(ptr: *const CEachFileStatus);
pub(crate) fn UpdateRequestTaskInfo(taskId: u32, updateInfo: *const CUpdateInfo) -> bool;
pub(crate) fn HasRequestTaskRecord(taskId: u32) -> bool;
pub(crate) fn PublishStateChangeEvents(
bundleName: *const c_char,
bundleNameLen: u32,
taskId: u32,
state: i32,
);
pub(crate) fn RequestBackgroundNotify(
msg: RequestTaskMsg,
path: *const c_char,
pathLen: i32,
percent: u32,
);
}

View File

@ -0,0 +1,185 @@
// Copyright (C) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::HashMap;
use super::ffi::CEachFileStatus;
use super::notify::{EachFileStatus, Progress};
use crate::task::config::Action;
use crate::task::reason::Reason;
use crate::utils::c_wrapper::{CFileSpec, CFormItem};
use crate::utils::form_item::{FileSpec, FormItem};
use crate::utils::hashmap_to_string;
#[derive(Debug)]
pub(crate) struct TaskInfo {
pub(crate) bundle: String,
pub(crate) url: String,
pub(crate) data: String,
pub(crate) token: String,
pub(crate) form_items: Vec<FormItem>,
pub(crate) file_specs: Vec<FileSpec>,
pub(crate) title: String,
pub(crate) description: String,
pub(crate) mime_type: String,
pub(crate) progress: Progress,
pub(crate) extras: HashMap<String, String>,
pub(crate) each_file_status: Vec<EachFileStatus>,
pub(crate) common_data: CommonTaskInfo,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub(crate) struct CommonTaskInfo {
pub(crate) task_id: u32,
pub(crate) uid: u64,
pub(crate) action: u8,
pub(crate) mode: u8,
pub(crate) ctime: u64,
pub(crate) mtime: u64,
pub(crate) reason: u8,
pub(crate) gauge: bool,
pub(crate) retry: bool,
pub(crate) tries: u32,
pub(crate) version: u8,
pub(crate) priority: u32,
}
pub(crate) struct InfoSet {
pub(crate) form_items: Vec<CFormItem>,
pub(crate) file_specs: Vec<CFileSpec>,
pub(crate) sizes: String,
pub(crate) processed: String,
pub(crate) extras: String,
pub(crate) each_file_status: Vec<CEachFileStatus>,
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u8)]
pub(crate) enum Mode {
BackGround = 0,
FrontEnd,
Any,
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(u8)]
pub(crate) enum State {
Initialized = 0x00,
Waiting = 0x10,
Running = 0x20,
Retrying = 0x21,
Paused = 0x30,
Stopped = 0x31,
Completed = 0x40,
Failed = 0x41,
Removed = 0x50,
Created = 0x60,
Any,
}
pub(crate) struct UpdateInfo {
pub(crate) mtime: u64,
pub(crate) reason: u8,
pub(crate) tries: u32,
pub(crate) mime_type: String,
pub(crate) progress: Progress,
pub(crate) each_file_status: Vec<EachFileStatus>,
}
impl From<u8> for Mode {
fn from(value: u8) -> Self {
match value {
0 => Mode::BackGround,
1 => Mode::FrontEnd,
_ => Mode::Any,
}
}
}
impl From<u8> for State {
fn from(value: u8) -> Self {
match value {
0 => State::Initialized,
16 => State::Waiting,
32 => State::Running,
33 => State::Retrying,
48 => State::Paused,
49 => State::Stopped,
64 => State::Completed,
65 => State::Failed,
80 => State::Removed,
96 => State::Created,
_ => State::Any,
}
}
}
impl TaskInfo {
pub(crate) fn build_info_set(&self) -> InfoSet {
InfoSet {
form_items: self.form_items.iter().map(|x| x.to_c_struct()).collect(),
file_specs: self.file_specs.iter().map(|x| x.to_c_struct()).collect(),
sizes: format!("{:?}", self.progress.sizes),
processed: format!("{:?}", self.progress.processed),
extras: hashmap_to_string(&self.extras),
each_file_status: self
.each_file_status
.iter()
.map(|x| x.to_c_struct())
.collect(),
}
}
}
#[derive(Debug)]
pub(crate) struct DumpAllInfo {
pub(crate) vec: Vec<DumpAllEachInfo>,
}
#[derive(Debug)]
pub(crate) struct DumpAllEachInfo {
pub(crate) task_id: u32,
pub(crate) action: Action,
pub(crate) state: State,
pub(crate) reason: Reason,
}
#[derive(Debug)]
pub(crate) struct DumpOneInfo {
pub(crate) task_id: u32,
pub(crate) action: Action,
pub(crate) state: State,
pub(crate) reason: Reason,
pub(crate) total_size: i64,
pub(crate) tran_size: usize,
pub(crate) url: String,
}
#[derive(Clone, Copy, PartialEq, Debug, Eq, PartialOrd, Ord)]
pub(crate) enum ApplicationState {
Foreground = 2,
Background = 4,
Terminated = 5,
}
impl From<u8> for ApplicationState {
fn from(value: u8) -> Self {
match value {
2 => ApplicationState::Foreground,
4 => ApplicationState::Background,
5 => ApplicationState::Terminated,
_ => panic!("wrong application value"),
}
}
}

Some files were not shown because too many files have changed in this diff Show More