按需启停优化需求

Change-Id: I38634d9f19680fa7fee741508a29674cea18b273
Signed-off-by: shawnluxy <luxinyi4@huawei.com>
This commit is contained in:
shawnluxy 2023-11-14 13:47:14 +08:00
parent 4088fecdb4
commit 837d54e145
24 changed files with 1133 additions and 43 deletions

View File

@ -47,7 +47,8 @@
"distributed_notification_service",
"c_utils",
"netstack",
"ylong_runtime"
"ylong_runtime",
"storage_service"
],
"third_party": [
"curl",

View File

@ -65,12 +65,14 @@ request_deps = [
request_external_deps = [
"ability_base:zuri",
"ability_runtime:abilitykit_native",
"ability_runtime:app_context",
"ability_runtime:data_ability_helper",
"ability_runtime:napi_base_context",
"c_utils:utils",
"hilog:libhilog",
"ipc:ipc_single",
"napi:ace_napi",
"storage_service:storage_manager_acl",
]
ohos_shared_library("request") {

View File

@ -23,6 +23,10 @@
namespace OHOS::Request {
static constexpr uint32_t TOKEN_MAX_BYTES = 2048;
static constexpr uint32_t TOKEN_MIN_BYTES = 8;
static constexpr int ACL_SUCC = 0;
static const std::string SA_PERMISSION_RWX = "g:3815:rwx";
static const std::string SA_PERMISSION_X = "g:3815:x";
static const std::string SA_PERMISSION_CLEAN = "g:3815:---";
class JsInitialize {
public:
JsInitialize() = default;
@ -32,6 +36,7 @@ public:
static void CreatProperties(napi_env env, napi_value &self, napi_value config, JsTask *task);
static napi_status GetContext(napi_env env, napi_value value,
std::shared_ptr<OHOS::AbilityRuntime::Context>& context);
static bool GetBaseDir(std::string &baseDir);
private:
static ExceptionError InitParam(napi_env env, napi_value* argv,
std::shared_ptr<OHOS::AbilityRuntime::Context> &context, Config &config);

View File

@ -46,11 +46,15 @@ public:
static void ClearTaskMap(const std::string &key);
static void AddTaskMap(const std::string &key, JsTask* task);
static bool SetPathPermission(const std::string &filepath);
static void RemovePathMap(const std::string &filepath);
static void ClearTaskContext(const std::string &key);
Config config_;
static std::mutex taskMutex_;
static std::map<std::string, JsTask*> taskMap_;
static std::mutex pathMutex_;
static std::map<std::string, int32_t> pathMap_;
std::mutex listenerMutex_;
std::map<std::string, std::vector<sptr<RequestNotify>>> listenerMap_;
private:
@ -94,6 +98,8 @@ private:
static bool ParseTouch(napi_env env, size_t argc, napi_value *argv, std::shared_ptr<TouchContext> context);
static int64_t ParseBefore(napi_env env, napi_value value);
static int64_t ParseAfter(napi_env env, napi_value value, int64_t before);
static void AddPathMap(const std::string &filepath, const std::string &baseDir);
static void ResetDirAccess(const std::string &filepath);
static void AddTaskContextMap(const std::string &key, std::shared_ptr<ContextInfo> context);
static void UnrefTaskContextMap(std::shared_ptr<ContextInfo> context);
static void UvUnrefTaskContext(uv_work_t *work, int status);

View File

@ -18,6 +18,8 @@
#include <cstring>
#include <regex>
#include <securec.h>
#include <fstream>
#include <sys/stat.h>
#include "js_common.h"
#include "log.h"
@ -28,7 +30,6 @@ static constexpr const char *PARAM_KEY_DESCRIPTION = "description";
static constexpr const char *PARAM_KEY_NETWORKTYPE = "networkType";
static constexpr const char *PARAM_KEY_FILE_PATH = "filePath";
static constexpr const char *PARAM_KEY_BACKGROUND = "background";
static constexpr uint32_t FILE_PERMISSION = 0644;
static constexpr uint32_t TITLE_MAXIMUM = 256;
static constexpr uint32_t DESCRIPTION_MAXIMUM = 1024;
static constexpr uint32_t URL_MAXIMUM = 2048;
@ -126,6 +127,21 @@ napi_status JsInitialize::GetContext(napi_env env, napi_value value,
return napi_ok;
}
bool JsInitialize::GetBaseDir(std::string &baseDir)
{
auto context = AbilityRuntime::Context::GetApplicationContext();
if (context == nullptr) {
REQUEST_HILOGE("AppContext is null.");
return false;
}
baseDir = context->GetBaseDir();
if (baseDir.empty()) {
REQUEST_HILOGE("Base dir not found.");
return false;
}
return true;
}
ExceptionError JsInitialize::CheckFilePath(const std::shared_ptr<OHOS::AbilityRuntime::Context> &context,
Config &config)
{
@ -150,6 +166,9 @@ ExceptionError JsInitialize::CheckFilePath(const std::shared_ptr<OHOS::AbilityRu
if (file.name.empty()) {
file.name = "file";
}
if (!JsTask::SetPathPermission(file.uri)) {
return { .code = E_FILE_IO, .errInfo = "set path permission fail" };
}
err = GetFD(path, config, file.fd);
if (err.code != E_OK) {
return err;
@ -184,11 +203,16 @@ ExceptionError JsInitialize::CheckUploadBodyFiles(Config &config, const std::str
int32_t bodyFd = open(fileName.c_str(), O_TRUNC | O_RDWR);
if (bodyFd < 0) {
bodyFd = open(fileName.c_str(), O_CREAT | O_RDWR, FILE_PERMISSION);
bodyFd = open(fileName.c_str(), O_CREAT | O_RDWR);
if (bodyFd < 0) {
return { .code = E_FILE_IO, .errInfo = "Failed to open file errno " + std::to_string(errno) };
}
}
if (bodyFd >= 0) {
chmod(fileName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH);
}
config.bodyFds.push_back(bodyFd);
config.bodyFileNames.push_back(fileName);
}
@ -202,8 +226,12 @@ ExceptionError JsInitialize::GetFD(const std::string &path, const Config &config
if (fd >= 0) {
REQUEST_HILOGD("File already exists");
if (config.action == Action::UPLOAD) {
chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
return error;
} else {
chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH);
}
if (config.version == Version::API10 && config.overwrite) {
return error;
}
@ -214,10 +242,11 @@ ExceptionError JsInitialize::GetFD(const std::string &path, const Config &config
ExceptionErrorCode code = config.version == Version::API10 ? E_FILE_IO : E_FILE_PATH;
return { .code = code, .errInfo = "Failed to open file errno " + std::to_string(errno) };
}
fd = open(path.c_str(), O_CREAT | O_RDWR, FILE_PERMISSION);
fd = open(path.c_str(), O_CREAT | O_RDWR);
if (fd < 0) {
return { .code = E_FILE_IO, .errInfo = "Failed to open file errno " + std::to_string(errno) };
}
chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | S_IWOTH);
}
return error;
}

View File

@ -19,6 +19,7 @@
#include <cstring>
#include <mutex>
#include <securec.h>
#include <sys/stat.h>
#include "async_call.h"
#include "js_initialize.h"
@ -29,6 +30,8 @@
#include "request_event.h"
#include "request_manager.h"
#include "upload/upload_task_napiV5.h"
#include "storage_acl.h"
using namespace OHOS::StorageDaemon;
namespace OHOS::Request {
constexpr int64_t MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
@ -40,6 +43,8 @@ std::mutex JsTask::requestFileMutex_;
thread_local napi_ref JsTask::requestFileCtor = nullptr;
std::mutex JsTask::taskMutex_;
std::map<std::string, JsTask *> JsTask::taskMap_;
std::mutex JsTask::pathMutex_;
std::map<std::string, int32_t> JsTask::pathMap_;
std::mutex JsTask::taskContextMutex_;
std::map<std::string, std::shared_ptr<JsTask::ContextInfo>> JsTask::taskContextMap_;
@ -670,6 +675,88 @@ void JsTask::ClearTaskMap(const std::string &key)
taskMap_.erase(it);
}
bool JsTask::SetPathPermission(const std::string &filepath)
{
std::string baseDir;
if (!JsInitialize::GetBaseDir(baseDir) || filepath.find(baseDir) == std::string::npos) {
REQUEST_HILOGE("File dir not found.");
return false;
}
AddPathMap(filepath, baseDir);
for (auto it : pathMap_) {
if (it.second <= 0) {
continue;
}
if (AclSetAccess(it.first, SA_PERMISSION_X) != ACL_SUCC) {
REQUEST_HILOGE("AclSetAccess Parent Dir Failed.");
return false;
}
}
std::string childDir = filepath.substr(0, filepath.rfind("/"));
if (AclSetAccess(childDir, SA_PERMISSION_RWX) != ACL_SUCC) {
REQUEST_HILOGE("AclSetAccess Child Dir Failed.");
return false;
}
return true;
}
void JsTask::AddPathMap(const std::string &filepath, const std::string &baseDir)
{
std::string childDir(filepath);
std::string parentDir;
while (childDir.length() > baseDir.length()) {
parentDir = childDir.substr(0, childDir.rfind("/"));
std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
auto it = pathMap_.find(parentDir);
if (it == pathMap_.end()) {
pathMap_[parentDir] = 1;
} else {
pathMap_[parentDir] += 1;
}
childDir = parentDir;
}
}
void JsTask::ResetDirAccess(const std::string &filepath)
{
int ret = AclSetAccess(filepath, SA_PERMISSION_CLEAN);
if (ret != ACL_SUCC) {
REQUEST_HILOGE("AclSetAccess Reset Dir Failed.");
}
}
void JsTask::RemovePathMap(const std::string &filepath)
{
std::string baseDir;
if (!JsInitialize::GetBaseDir(baseDir) || filepath.find(baseDir) == std::string::npos) {
REQUEST_HILOGE("File dir not found.");
return;
}
if (chmod(filepath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) {
REQUEST_HILOGE("File remove WOTH access Failed.");
}
std::string childDir(filepath);
std::string parentDir;
while (childDir.length() > baseDir.length()) {
parentDir = childDir.substr(0, childDir.rfind("/"));
std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
auto it = pathMap_.find(parentDir);
if (it != pathMap_.end()) {
if (pathMap_[parentDir] <= 1) {
pathMap_.erase(parentDir);
ResetDirAccess(parentDir);
} else {
pathMap_[parentDir] -= 1;
}
}
childDir = parentDir;
}
}
void JsTask::ClearTaskContext(const std::string &key)
{
std::lock_guard<std::mutex> lockGuard(JsTask::taskContextMutex_);

View File

@ -200,6 +200,9 @@ void NotifyStub::OnDone(MessageParcel &data)
return;
}
RequestEvent::AddCache(taskInfo->tid, taskInfo);
for (auto &file : taskInfo->files) {
JsTask::RemovePathMap(file.uri);
}
JsTask::ClearTaskContext(taskInfo->tid);
}
} // namespace OHOS::Request

View File

@ -88,7 +88,6 @@ void RequestServiceProxy::GetVectorData(const Config &config, MessageParcel &dat
data.WriteString(file.uri);
data.WriteString(file.filename);
data.WriteString(file.type);
data.WriteFileDescriptor(file.fd);
data.WriteInt32(static_cast<int32_t>(errno));
}
@ -97,15 +96,16 @@ void RequestServiceProxy::GetVectorData(const Config &config, MessageParcel &dat
close(file.fd);
}
}
// Response Bodys fds.
data.WriteUint32(config.bodyFds.size());
for (const auto &fd : config.bodyFds) {
data.WriteFileDescriptor(fd);
if (fd > 0) {
close(fd);
}
}
for (const auto &name : config.bodyFileNames) {
data.WriteString(name);
}
data.WriteUint32(config.headers.size());
for (const auto &header : config.headers) {

View File

@ -6,7 +6,15 @@
"libpath": "libdownload_server.dylib.so",
"run-on-create": false,
"distributed": false,
"dump_level": 1
"dump_level": 1,
"start-on-demand": {
"commonevent": [
{
"name": "usual.event.CONNECTIVITY_CHANGE",
"value": "3"
}
]
}
}
]
}

View File

@ -114,6 +114,7 @@ ohos_shared_library("request_service_c") {
"${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",

View File

@ -23,6 +23,7 @@
#include "c_filter.h"
#include "c_progress.h"
#include "c_task_info.h"
#include "c_task_config.h"
#include "rdb_errno.h"
#include "rdb_helper.h"
#include "rdb_open_callback.h"
@ -65,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, "
"body_file_names_len INTEGER)";
constexpr const char *CREATE_REQUEST_TABLE2 = "CREATE TABLE IF NOT EXISTS task_info_attachment "
"(id INTEGER PRIMARY KEY AUTOINCREMENT, "
@ -78,7 +80,40 @@ constexpr const char *CREATE_REQUEST_TABLE2 = "CREATE TABLE IF NOT EXISTS task_i
"file_name TEXT, "
"mime_type TEXT, "
"reason INTEGER, "
"message TEXT)";
"message TEXT, "
"body_file_name TEXT)";
constexpr const char *CREATE_REQUEST_TABLE3 = "CREATE TABLE IF NOT EXISTS request_task_config "
"(id INTEGER PRIMARY KEY AUTOINCREMENT, "
"task_id INTEGER, "
"uid INTEGER, "
"action INTEGER, "
"mode INTEGER, "
"cover INTEGER, "
"network INTEGER, "
"meterd INTEGER, "
"roaming INTEGER, "
"retry INTEGER, "
"redirect INTEGER, "
"idx INTEGER, "
"begins INTEGER, "
"ends INTEGER, "
"gauge INTEGER, "
"precise INTEGER, "
"background INTEGER, "
"bundle TEXT, "
"url TEXT, "
"titile TEXT, "
"description TEXT, "
"method TEXT, "
"headers TEXT, "
"data TEXT, "
"token TEXT, "
"extras TEXT, "
"version INTEGER, "
"form_items_len INTEGER, "
"file_specs_len INTEGER, "
"body_file_names_len INTEGER)";
class RequestDataBase {
public:
@ -89,6 +124,7 @@ public:
bool Update(const OHOS::NativeRdb::ValuesBucket values, const OHOS::NativeRdb::AbsRdbPredicates &predicates);
std::shared_ptr<OHOS::NativeRdb::ResultSet> Query(const OHOS::NativeRdb::AbsRdbPredicates &predicates,
const std::vector<std::string> &columns);
bool Delete(const OHOS::NativeRdb::AbsRdbPredicates &predicates);
bool BeginTransaction();
bool Commit();
bool RollBack();
@ -134,6 +170,17 @@ int QueryTaskInfoAttachment(const OHOS::NativeRdb::RdbPredicates &rdbPredicates,
int64_t fileSpecsLen);
CTaskInfo *BuildCTaskInfo(const TaskInfo &taskInfo);
CProgress BuildCProgress(const Progress &progress);
bool HasTaskConfigRecord(uint32_t taskId);
bool RecordRequestTaskConfig(CTaskConfig *taskConfig);
void GetCommonTaskConfig(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, TaskConfig &taskConfig);
CTaskConfig **QueryAllTaskConfig();
int QueryTaskConfigLen();
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);
CTaskConfig **BuildCTaskConfigs(const std::vector<TaskConfig> &taskConfigs);
bool CleanTaskConfigTable(uint32_t taskId, uint64_t uid);
void DeleteCTaskConfigs(CTaskConfig **ptr);
#ifdef __cplusplus
}

View File

@ -0,0 +1,98 @@
/*
* 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.
*/
#ifndef C_TASK_CONFIG_H
#define C_TASK_CONFIG_H
#include <cstdint>
#include <stdint.h>
#include <string>
#include <vector>
#include <map>
#include "c_form_item.h"
#include "c_string_wrapper.h"
struct CommonTaskConfig {
uint32_t taskId;
uint64_t uid;
uint8_t action;
uint8_t mode;
bool cover;
uint8_t network;
bool meterd;
bool roaming;
bool retry;
bool redirect;
uint32_t index;
uint64_t begins;
int64_t ends;
bool gauge;
bool precise;
bool background;
};
struct CStringMap {
CStringWrapper key;
CStringWrapper value;
};
struct CTaskConfig {
CStringWrapper bundle;
CStringWrapper url;
CStringWrapper title;
CStringWrapper description;
CStringWrapper method;
CStringWrapper headers;
CStringWrapper data;
CStringWrapper token;
CStringWrapper extras;
uint8_t version;
CFormItem *formItemsPtr;
uint32_t formItemsLen;
CFileSpec *fileSpecsPtr;
uint32_t fileSpecsLen;
CStringWrapper *bodyFileNamesPtr;
uint32_t bodyFileNamesLen;
CommonTaskConfig commonData;
};
struct TaskConfig {
std::string bundle;
std::string url;
std::string title;
std::string description;
std::string method;
std::string headers;
std::string data;
std::string token;
std::string extras;
uint8_t version;
std::vector<FormItem> formItems;
std::vector<FileSpec> fileSpecs;
std::vector<std::string> bodyFileNames;
CommonTaskConfig commonData;
};
#ifdef __cplusplus
extern "C" {
#endif
void DeleteCTaskConfig(CTaskConfig *ptr);
#ifdef __cplusplus
}
#endif
#endif // C_TASK_CONFIG_H

View File

@ -60,6 +60,8 @@ struct CTaskInfo {
uint32_t formItemsLen;
CFileSpec *fileSpecsPtr;
uint32_t fileSpecsLen;
CStringWrapper *bodyFileNamesPtr;
uint32_t bodyFileNamesLen;
CStringWrapper title;
CStringWrapper description;
CStringWrapper mimeType;
@ -76,6 +78,7 @@ struct TaskInfo {
std::string token;
std::vector<FormItem> formItems;
std::vector<FileSpec> fileSpecs;
std::vector<std::string> bodyFileNames;
std::string title;
std::string description;
std::string mimeType;
@ -98,6 +101,7 @@ extern "C" {
void DeleteCFormItem(CFormItem *ptr);
void DeleteCFileSpec(CFileSpec *ptr);
void DeleteCStringPtr(CStringWrapper *ptr);
void DeleteCEachFileStatus(CEachFileStatus *ptr);
void DeleteCTaskInfo(CTaskInfo *ptr);

View File

@ -108,6 +108,19 @@ std::shared_ptr<OHOS::NativeRdb::ResultSet> RequestDataBase::Query(const OHOS::N
return store_->Query(predicates, columns);
}
bool RequestDataBase::Delete(const OHOS::NativeRdb::AbsRdbPredicates &predicates)
{
if (store_ == nullptr) {
REQUEST_HILOGE("store_ is nullptr");
return false;
}
int deletedRows = 0;
int ret = store_->Delete(deletedRows, predicates);
REQUEST_HILOGI("request database delete ret is %{public}d, rows: %{public}d", ret, deletedRows);
return ret == OHOS::NativeRdb::E_OK;
}
int RequestDBOpenCallback::OnCreate(OHOS::NativeRdb::RdbStore &store)
{
int ret = store.ExecuteSql(CREATE_REQUEST_TABLE1);
@ -120,6 +133,11 @@ int RequestDBOpenCallback::OnCreate(OHOS::NativeRdb::RdbStore &store)
REQUEST_HILOGE("create table2 error, ret = %{public}d", ret);
return ret;
}
ret = store.ExecuteSql(CREATE_REQUEST_TABLE3);
if (ret != OHOS::NativeRdb::E_OK) {
REQUEST_HILOGE("create table3 error, ret = %{public}d", ret);
return ret;
}
REQUEST_HILOGI("create table success");
return OHOS::NativeRdb::E_OK;
}
@ -184,6 +202,7 @@ bool WriteRequestTaskInfo(CTaskInfo *taskInfo)
insertValues.PutString("extras", std::string(taskInfo->progress.extras.cStr, taskInfo->progress.extras.len));
insertValues.PutLong("form_items_len", taskInfo->formItemsLen);
insertValues.PutLong("file_specs_len", taskInfo->fileSpecsLen);
insertValues.PutLong("body_file_names_len", taskInfo->bodyFileNamesLen);
if (!OHOS::Request::RequestDataBase::GetInstance().Insert(std::string("request_task_info"), insertValues)) {
REQUEST_HILOGE("insert to request_task_info failed");
return false;
@ -194,8 +213,8 @@ bool WriteRequestTaskInfo(CTaskInfo *taskInfo)
bool WriteTaskInfoAttachment(CTaskInfo *taskInfo)
{
REQUEST_HILOGD("write to task_info_attachment");
uint64_t len = std::max(taskInfo->formItemsLen, taskInfo->fileSpecsLen);
REQUEST_HILOGI("write to task_info_attachment");
uint64_t len = std::max({taskInfo->formItemsLen, taskInfo->fileSpecsLen, taskInfo->bodyFileNamesLen});
for (uint64_t i = 0; i < len; i++) {
OHOS::NativeRdb::ValuesBucket insertValues;
insertValues.PutInt("task_id", taskInfo->commonData.taskId);
@ -219,6 +238,10 @@ bool WriteTaskInfoAttachment(CTaskInfo *taskInfo)
insertValues.PutString("message", std::string(taskInfo->eachFileStatusPtr[i].message.cStr,
taskInfo->eachFileStatusPtr[i].message.len));
}
if (i < taskInfo->bodyFileNamesLen) {
insertValues.PutString("body_file_name",
std::string(taskInfo->bodyFileNamesPtr[i].cStr, taskInfo->bodyFileNamesPtr[i].len));
}
if (!OHOS::Request::RequestDataBase::GetInstance().Insert(std::string("task_info_attachment"), insertValues)) {
REQUEST_HILOGE("insert to task_info_attachment failed");
return false;
@ -565,6 +588,12 @@ CTaskInfo *BuildCTaskInfo(const TaskInfo &taskInfo)
eachFileStatusPtr[i].message = WrapperCString(taskInfo.eachFileStatus[i].message);
}
uint32_t bodyFileNamesLen = taskInfo.bodyFileNames.size();
CStringWrapper *bodyFileNamesPtr = new CStringWrapper[bodyFileNamesLen];
for (uint32_t i = 0; i < bodyFileNamesLen; i++) {
bodyFileNamesPtr[i] = WrapperCString(taskInfo.bodyFileNames[i]);
}
CTaskInfo *cTaskInfo = new CTaskInfo;
cTaskInfo->bundle = WrapperCString(taskInfo.bundle);
cTaskInfo->url = WrapperCString(taskInfo.url);
@ -574,6 +603,8 @@ CTaskInfo *BuildCTaskInfo(const TaskInfo &taskInfo)
cTaskInfo->formItemsLen = formItemsLen;
cTaskInfo->fileSpecsPtr = fileSpecsPtr;
cTaskInfo->fileSpecsLen = fileSpecsLen;
cTaskInfo->bodyFileNamesPtr = bodyFileNamesPtr;
cTaskInfo->bodyFileNamesLen = bodyFileNamesLen;
cTaskInfo->title = WrapperCString(taskInfo.title);
cTaskInfo->description = WrapperCString(taskInfo.description);
cTaskInfo->mimeType = WrapperCString(taskInfo.mimeType);
@ -592,4 +623,303 @@ CProgress BuildCProgress(const Progress &progress)
.processed = WrapperCString(progress.processed),
.extras = WrapperCString(progress.extras),
};
}
bool HasTaskConfigRecord(uint32_t taskId)
{
OHOS::NativeRdb::RdbPredicates rdbPredicates("request_task_config");
rdbPredicates.EqualTo("task_id", std::to_string(taskId));
auto resultSet = OHOS::Request::RequestDataBase::GetInstance().Query(rdbPredicates, { "task_id" });
if (resultSet == nullptr) {
REQUEST_HILOGE("TaskConfig result set is nullptr");
return false;
}
int rowCount = 0;
if (resultSet->GetRowCount(rowCount) != OHOS::NativeRdb::E_OK) {
REQUEST_HILOGE("TaskConfig result count row failed");
return false;
}
if (rowCount == 0) {
return false;
}
REQUEST_HILOGI("has the task record in task_config database");
return true;
}
bool RecordRequestTaskConfig(CTaskConfig *taskConfig)
{
REQUEST_HILOGI("write to request_task_config");
OHOS::NativeRdb::ValuesBucket insertValues;
insertValues.PutLong("task_id", taskConfig->commonData.taskId);
insertValues.PutLong("uid", taskConfig->commonData.uid);
insertValues.PutInt("action", taskConfig->commonData.action);
insertValues.PutInt("mode", taskConfig->commonData.mode);
insertValues.PutInt("cover", taskConfig->commonData.cover);
insertValues.PutInt("network", taskConfig->commonData.network);
insertValues.PutInt("meterd", taskConfig->commonData.meterd);
insertValues.PutInt("roaming", taskConfig->commonData.roaming);
insertValues.PutInt("retry", taskConfig->commonData.retry);
insertValues.PutInt("redirect", taskConfig->commonData.redirect);
insertValues.PutLong("idx", taskConfig->commonData.index);
insertValues.PutLong("begins", taskConfig->commonData.begins);
insertValues.PutLong("ends", taskConfig->commonData.ends);
insertValues.PutInt("gauge", taskConfig->commonData.gauge);
insertValues.PutInt("precise", taskConfig->commonData.precise);
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));
insertValues.PutString("titile", std::string(taskConfig->title.cStr, taskConfig->title.len));
insertValues.PutString("description", std::string(taskConfig->description.cStr, taskConfig->description.len));
insertValues.PutString("method", std::string(taskConfig->method.cStr, taskConfig->method.len));
insertValues.PutString("headers", std::string(taskConfig->headers.cStr, taskConfig->headers.len));
insertValues.PutString("data", std::string(taskConfig->data.cStr, taskConfig->data.len));
insertValues.PutString("token", std::string(taskConfig->token.cStr, taskConfig->token.len));
insertValues.PutString("extras", std::string(taskConfig->extras.cStr, taskConfig->extras.len));
insertValues.PutInt("version", taskConfig->version);
insertValues.PutLong("form_items_len", taskConfig->formItemsLen);
insertValues.PutLong("file_specs_len", taskConfig->fileSpecsLen);
insertValues.PutLong("body_file_names_len", taskConfig->bodyFileNamesLen);
if (!OHOS::Request::RequestDataBase::GetInstance().Insert(std::string("request_task_config"), insertValues)) {
REQUEST_HILOGE("insert to request_task_config failed");
return false;
}
REQUEST_HILOGI("insert to request_task_config success");
return true;
}
void GetCommonTaskConfig(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, TaskConfig &taskConfig)
{
int64_t taskId = 0;
int64_t uid = 0;
int action = 0;
int mode = 0;
int cover = 0;
int network = 0;
int meterd = 0;
int roaming = 0;
int retry = 0;
int redirect = 0;
int64_t index = 0;
int64_t begins = 0;
int64_t ends = 0;
int gauge = 0;
int precise = 0;
int background = 0;
resultSet->GetLong(0, taskId);
taskConfig.commonData.taskId = static_cast<uint32_t>(taskId);
resultSet->GetLong(1, uid);
taskConfig.commonData.uid = static_cast<uint64_t>(uid);
resultSet->GetInt(2, action);
taskConfig.commonData.action = static_cast<uint8_t>(action);
resultSet->GetInt(3, mode);
taskConfig.commonData.mode = static_cast<uint8_t>(mode);
resultSet->GetInt(4, cover);
taskConfig.commonData.cover = static_cast<bool>(cover);
resultSet->GetInt(5, network);
taskConfig.commonData.network = static_cast<uint8_t>(network);
resultSet->GetInt(6, meterd);
taskConfig.commonData.meterd = static_cast<bool>(meterd);
resultSet->GetInt(7, roaming);
taskConfig.commonData.roaming = static_cast<bool>(roaming);
resultSet->GetInt(8, retry);
taskConfig.commonData.retry = static_cast<bool>(retry);
resultSet->GetInt(9, redirect);
taskConfig.commonData.redirect = static_cast<bool>(redirect);
resultSet->GetLong(10, index);
taskConfig.commonData.index = static_cast<uint32_t>(index);
resultSet->GetLong(11, begins);
taskConfig.commonData.begins = static_cast<uint64_t>(begins);
resultSet->GetLong(12, ends);
taskConfig.commonData.ends = static_cast<int64_t>(ends);
resultSet->GetInt(13, gauge);
taskConfig.commonData.gauge = static_cast<bool>(gauge);
resultSet->GetInt(14, precise);
taskConfig.commonData.precise = static_cast<bool>(precise);
resultSet->GetInt(15, background);
taskConfig.commonData.background = static_cast<bool>(background);
}
CTaskConfig **QueryAllTaskConfig()
{
OHOS::NativeRdb::RdbPredicates rdbPredicates("request_task_config");
std::vector<TaskConfig> taskConfigs;
if (QueryRequestTaskConfig(rdbPredicates, taskConfigs) == OHOS::Request::QUERY_ERR) {
return nullptr;
}
return BuildCTaskConfigs(taskConfigs);
}
int QueryTaskConfigLen()
{
OHOS::NativeRdb::RdbPredicates rdbPredicates("request_task_config");
auto resultSet = OHOS::Request::RequestDataBase::GetInstance().Query(rdbPredicates, { "task_id", "uid" });
int len = 0;
if (resultSet == nullptr || resultSet->GetRowCount(len) != OHOS::NativeRdb::E_OK) {
REQUEST_HILOGE("Get TaskConfigs length failed");
return OHOS::Request::QUERY_ERR;
}
return len;
}
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" });
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");
return OHOS::Request::QUERY_ERR;
}
for (auto i = 0; i < rowCount; i++) {
if (resultSet->GoToRow(i) != OHOS::NativeRdb::E_OK) {
REQUEST_HILOGE("TaskConfig result set go to %{public}d row failed", i);
return OHOS::Request::QUERY_ERR;
}
TaskConfig taskConfig;
int version = 0;
int64_t formItemsLen = 0;
int64_t fileSpecsLen = 0;
int64_t bodyFileNamesLen = 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);
taskConfig.version = static_cast<uint8_t>(version);
resultSet->GetLong(26, formItemsLen);
resultSet->GetLong(27, fileSpecsLen);
resultSet->GetLong(28, bodyFileNamesLen);
OHOS::NativeRdb::RdbPredicates rdbPredicates("task_info_attachment");
rdbPredicates.EqualTo("task_id", std::to_string(taskConfig.commonData.taskId))
->And()->EqualTo("uid", std::to_string(taskConfig.commonData.uid));
if (QueryTaskConfigAttachment(rdbPredicates, taskConfig, formItemsLen, fileSpecsLen, bodyFileNamesLen)
== OHOS::Request::QUERY_ERR) {
return OHOS::Request::QUERY_ERR;
}
taskConfigs.push_back(std::move(taskConfig));
}
resultSet->Close();
return OHOS::Request::QUERY_OK;
}
int QueryTaskConfigAttachment(const OHOS::NativeRdb::RdbPredicates &rdbPredicates, TaskConfig &taskConfig,
int64_t formItemsLen, int64_t fileSpecsLen, int64_t bodyFileNamesLen)
{
auto resultSet = OHOS::Request::RequestDataBase::GetInstance().Query(rdbPredicates,
{ "form_item_name", "value", "file_spec_name", "path", "file_name", "mime_type", "body_file_name" });
if (resultSet == nullptr) {
REQUEST_HILOGE("ConfigAttach result set is nullptr");
return OHOS::Request::QUERY_ERR;
}
int rowCount = 0;
if (resultSet->GetRowCount(rowCount) != OHOS::NativeRdb::E_OK) {
REQUEST_HILOGI("query task_config_attachment get row count failed");
}
int64_t len = std::max({formItemsLen, fileSpecsLen, bodyFileNamesLen});
if (rowCount != len) {
REQUEST_HILOGI("query task_config_attachment row count %{public}d != max len %{public}lld", rowCount, len);
return OHOS::Request::QUERY_ERR;
}
for (int64_t i = 0; i < len; i++) {
if (resultSet->GoToRow(i) != OHOS::NativeRdb::E_OK) {
REQUEST_HILOGE("ConfigAttach result set go to %{public}" PRId64 "row failed", i);
return OHOS::Request::QUERY_ERR;
}
if (i < formItemsLen) {
FormItem formItem;
resultSet->GetString(0, formItem.name);
resultSet->GetString(1, formItem.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);
taskConfig.fileSpecs.push_back(std::move(fileSpec));
}
if (i < bodyFileNamesLen) {
std::string bodyFileName;
resultSet->GetString(6, bodyFileName);
taskConfig.bodyFileNames.push_back(std::move(bodyFileName));
}
}
resultSet->Close();
return OHOS::Request::QUERY_OK;
}
CTaskConfig **BuildCTaskConfigs(const std::vector<TaskConfig> &taskConfigs)
{
CTaskConfig **cTaskConfigs = new CTaskConfig *[taskConfigs.size()];
for (unsigned int i = 0; i < taskConfigs.size(); i++) {
CTaskConfig *cTaskConfig = new CTaskConfig;
TaskConfig taskConfig = taskConfigs[i];
cTaskConfig->bundle = WrapperCString(taskConfig.bundle);
cTaskConfig->url = WrapperCString(taskConfig.url);
cTaskConfig->title = WrapperCString(taskConfig.title);
cTaskConfig->description = WrapperCString(taskConfig.description);
cTaskConfig->method = WrapperCString(taskConfig.method);
cTaskConfig->headers = WrapperCString(taskConfig.headers);
cTaskConfig->data = WrapperCString(taskConfig.data);
cTaskConfig->token = WrapperCString(taskConfig.token);
cTaskConfig->extras = WrapperCString(taskConfig.extras);
cTaskConfig->version = taskConfig.version;
uint32_t formItemsLen = taskConfig.formItems.size();
CFormItem *formItemsPtr = new CFormItem[formItemsLen];
for (uint32_t j = 0; j < formItemsLen; j++) {
formItemsPtr[j].name = WrapperCString(taskConfig.formItems[j].name);
formItemsPtr[j].value = WrapperCString(taskConfig.formItems[j].value);
}
uint32_t fileSpecsLen = taskConfig.fileSpecs.size();
CFileSpec *fileSpecsPtr = new CFileSpec[fileSpecsLen];
for (uint32_t j = 0; j < fileSpecsLen; j++) {
fileSpecsPtr[j].name = WrapperCString(taskConfig.fileSpecs[j].name);
fileSpecsPtr[j].path = WrapperCString(taskConfig.fileSpecs[j].path);
fileSpecsPtr[j].fileName = WrapperCString(taskConfig.fileSpecs[j].fileName);
fileSpecsPtr[j].mimeType = WrapperCString(taskConfig.fileSpecs[j].mimeType);
}
uint32_t bodyFileNamesLen = taskConfig.bodyFileNames.size();
CStringWrapper *bodyFileNamesPtr = new CStringWrapper[bodyFileNamesLen];
for (uint32_t j = 0; j < bodyFileNamesLen; j++) {
bodyFileNamesPtr[j] = WrapperCString(taskConfig.bodyFileNames[j]);
}
cTaskConfig->formItemsPtr = formItemsPtr;
cTaskConfig->formItemsLen = formItemsLen;
cTaskConfig->fileSpecsPtr = fileSpecsPtr;
cTaskConfig->fileSpecsLen = fileSpecsLen;
cTaskConfig->bodyFileNamesPtr = bodyFileNamesPtr;
cTaskConfig->bodyFileNamesLen = bodyFileNamesLen;
cTaskConfig->commonData = taskConfig.commonData;
cTaskConfigs[i] = std::move(cTaskConfig);
}
return cTaskConfigs;
}
bool CleanTaskConfigTable(uint32_t taskId, uint64_t uid)
{
OHOS::NativeRdb::RdbPredicates predicates("request_task_config");
predicates.EqualTo("task_id", std::to_string(taskId))->And()->EqualTo("uid", std::to_string(uid));
if (OHOS::Request::RequestDataBase::GetInstance().Delete(predicates)) {
REQUEST_HILOGE("task_config table deleted task_id: %{public}u", taskId);
return true;
}
return false;
}
void DeleteCTaskConfigs(CTaskConfig **ptr)
{
delete[] ptr;
}

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.
*/
#include "c_task_config.h"
void DeleteCTaskConfig(CTaskConfig *ptr)
{
delete[] ptr;
}

View File

@ -25,6 +25,11 @@ void DeleteCFileSpec(CFileSpec *ptr)
delete[] ptr;
}
void DeleteCStringPtr(CStringWrapper *ptr)
{
delete[] ptr;
}
void DeleteCEachFileStatus(CEachFileStatus *ptr)
{
delete[] ptr;

View File

@ -91,6 +91,24 @@ pub enum State {
ANY = 0x61,
}
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,
}
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(i32)]
pub enum ApplicationState {

View File

@ -16,7 +16,7 @@
#![allow(unused_variables)]
// C interface for check permission
use super::{enumration::*, progress::RequestTaskMsg, form_item::CFileSpec,
form_item::CFormItem, task_info::*, c_string_wrapper::*, filter::*};
form_item::CFormItem, task_info::*, task_config::*, c_string_wrapper::*, filter::*};
use std::ffi::{c_char, c_void};
type APPSTATECB = extern "C" fn(i32, i32);
@ -38,6 +38,9 @@ extern "C" {
pub fn GetNetworkInfo() -> *const NetworkInfo;
pub fn GetTopBundleName() -> CStringWrapper;
pub fn DeleteCTaskInfo(ptr: *const CTaskInfo);
pub fn DeleteCTaskConfig(ptr: *const CTaskConfig);
pub fn DeleteCTaskConfigs(ptr: *const*const CTaskConfig);
pub fn DeleteCStringPtr(ptr: *const CStringWrapper);
pub fn DeleteChar(ptr: *const c_char);
pub fn DeleteCFormItem(ptr: *const CFormItem);
pub fn DeleteCFileSpec(ptr: *const CFileSpec);
@ -49,6 +52,11 @@ extern "C" {
pub fn Touch(taskId: u32, uid: u64, token: CStringWrapper) -> *const CTaskInfo;
pub fn Query(taskId: u32, queryAction: Action) -> *const CTaskInfo;
pub fn Search(filter: CFilter) -> CVectorWrapper;
pub fn HasTaskConfigRecord(taskId: u32) -> bool;
pub fn RecordRequestTaskConfig(taskConfig: *const CTaskConfig) -> bool;
pub fn QueryAllTaskConfig() -> *const*const CTaskConfig;
pub fn QueryTaskConfigLen() -> i32;
pub fn CleanTaskConfigTable(taskId: u32, uid: u64) -> bool;
pub fn RequestIsSystemAPI(tokenId: u64) -> bool;
pub fn GetCallingBundle(tokenId: u64) -> CStringWrapper;
pub fn PublishStateChangeEvents(bundleName: *const c_char, bundleNameLen: u32, taskId: u32, state: i32);

View File

@ -80,6 +80,10 @@ impl RequestServiceInterface for RequestService {
let description: String = data.read()?;
let data_base: String = data.read()?;
let bundle = RequestAbility::get_ability_instance().get_calling_bundle();
let mut task_id: u32 = 0;
let uid: u64 = get_calling_uid();
let mut form_items = Vec::<FormItem>::new();
let form_size: u32 = data.read()?;
if form_size > data.get_readable_bytes() {
@ -106,8 +110,13 @@ impl RequestServiceInterface for RequestService {
let path: String = data.read()?;
let file_name: String = data.read()?;
let mime_type: String = data.read()?;
let fd = data.read::<FileDesc>()?;
files.push(File::from(fd));
if action == Action::UPLOAD{
let file = RequestAbility::open_file_readonly(uid, &bundle, &path)?;
files.push(file);
} else {
let file = RequestAbility::open_file_readwrite(uid, &bundle, &path)?;
files.push(file);
}
let fd_error: i32 = data.read()?;
file_specs.push(FileSpec {
name,
@ -120,9 +129,12 @@ impl RequestServiceInterface for RequestService {
// Response Bodys fd.
let body_file_size: u32 = data.read()?;
let mut body_files = Vec::new();
let mut body_file_names: Vec<String> = Vec::new();
for i in 0..body_file_size {
let fd = data.read::<FileDesc>()?;
body_files.push(File::from(fd));
let file_name: String = data.read()?;
let body_file = RequestAbility::open_file_readwrite(uid, &bundle, &file_name)?;
body_file_names.push(file_name);
body_files.push(body_file);
}
let header_size: u32 = data.read()?;
@ -150,7 +162,7 @@ impl RequestServiceInterface for RequestService {
let value: String = data.read()?;
extras.insert(key, value);
}
let bundle = RequestAbility::get_ability_instance().get_calling_bundle();
let task_config = TaskConfig {
bundle,
url,
@ -164,7 +176,10 @@ impl RequestServiceInterface for RequestService {
version,
form_items,
file_specs,
body_file_names,
common_data: CommonTaskConfig {
task_id ,
uid ,
action,
mode,
cover,
@ -182,7 +197,6 @@ impl RequestServiceInterface for RequestService {
},
};
debug!(LOG_LABEL, "files {:?}", @public(files));
let mut task_id: u32 = 0;
let ret =
RequestAbility::get_ability_instance().construct(task_config, files, body_files, &mut task_id);
let remote_object: RemoteObj = data.read::<RemoteObj>()?;
@ -552,7 +566,7 @@ impl RequestServiceInterface for RequestService {
/// start
pub fn start() {
RequestAbility::get_ability_instance().start();
RequestAbility::get_ability_instance();
}
/// stop

View File

@ -30,6 +30,7 @@ use std::{
collections::HashMap,
fmt::Debug,
fs::File,
fs::OpenOptions,
mem::MaybeUninit,
result::Result,
string::String,
@ -66,6 +67,7 @@ impl RequestAbility {
monitor_network();
monitor_app_state();
monitor_task();
ylong_runtime::spawn(restore_all_tasks());
ylong_runtime::spawn(unload_sa());
TaskManager::get_instance().dump_all_task_info();
0
@ -106,13 +108,13 @@ impl RequestAbility {
let version = config.version.clone();
let error = TaskManager::get_instance().construct_task(
Arc::new(config),
get_calling_uid(),
uid,
task_id,
files,
body_files,
);
if version != Version::API10 {
TaskManager::get_instance().start(get_calling_uid(), *task_id);
TaskManager::get_instance().start(uid, *task_id);
}
error
}
@ -282,6 +284,7 @@ impl RequestAbility {
ServerRunState::NoStart,
Mutex::new(HashMap::new()),
));
REQUESTABILITY.as_mut().unwrap().start();
});
REQUESTABILITY.as_mut().unwrap()
}
@ -529,4 +532,32 @@ impl RequestAbility {
task.file_total_size.load(Ordering::SeqCst),
task.progress.lock().unwrap().common_data.total_processed, task.conf.url).as_bytes());
}
pub fn convert_path(&self, 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, ""))
}
pub fn open_file_readwrite(uid: u64, bundle: &String, path: &String) -> IpcResult<File> {
match OpenOptions::new().read(true).write(true).truncate(true)
.open(RequestAbility::get_ability_instance().convert_path(uid, &bundle, &path)) {
Ok(file) => { Ok(file) },
Err(e) => {
error!(LOG_LABEL, "open_file_readwrite failed, err is {:?}", e);
Err(IpcStatusCode::Failed)
},
}
}
pub fn open_file_readonly(uid: u64, bundle: &String, path: &String) -> IpcResult<File> {
match OpenOptions::new().read(true)
.open(RequestAbility::get_ability_instance().convert_path(uid, &bundle, &path)) {
Ok(file) => { Ok(file) },
Err(e) => {
error!(LOG_LABEL, "open_file_readonly failed, err is {:?}", e);
Err(IpcStatusCode::Failed)
},
}
}
}

View File

@ -16,7 +16,7 @@
use std::{ffi::CString, ffi::c_char, fs::File, pin::Pin, thread::sleep, time::Duration, cell::UnsafeCell};
use super::{
enumration::*, progress::*, task_info::*, task_config::*, task_manager::*, utils::*, request_binding::*,
log::LOG_LABEL,
log::LOG_LABEL, request_service_ability::*,
};
use crate::trace::TraceScope;
use crate::sys_event::{SysEvent, build_number_param, build_str_param};
@ -100,6 +100,7 @@ pub struct RequestTask {
seek_flag: AtomicBool,
range_request: AtomicBool,
range_response: AtomicBool,
restored: AtomicBool,
skip_bytes: AtomicU64,
upload_counts: AtomicU32,
client: Option<Client>,
@ -333,6 +334,7 @@ impl RequestTask {
seek_flag: AtomicBool::new(false),
range_request: AtomicBool::new(false),
range_response: AtomicBool::new(false),
restored: AtomicBool::new(false),
skip_bytes: AtomicU64::new(0),
upload_counts: AtomicU32::new(0),
client: None,
@ -344,6 +346,80 @@ impl RequestTask {
task
}
pub fn restore_task(conf: Arc<TaskConfig>, info: TaskInfo) -> Self {
let progress_index = info.progress.common_data.index;
let uid = info.common_data.uid;
let action = conf.common_data.action;
let mut files: Vec<File> = Vec::new();
let mut body_files: Vec<File> = Vec::new();
for fs in &conf.file_specs {
if action == Action::UPLOAD {
match RequestAbility::open_file_readonly(uid, &conf.bundle, &fs.path) {
Ok(file) => { files.push(file); },
Err(e) => { error!(LOG_LABEL, "open file RO failed, err is {:?}", e); },
}
} else {
match RequestAbility::open_file_readwrite(uid, &conf.bundle, &fs.path) {
Ok(file) => { files.push(file); },
Err(e) => { error!(LOG_LABEL, "open file RW failed, err is {:?}", e); },
}
}
}
for name in &conf.body_file_names {
match RequestAbility::open_file_readwrite(uid, &conf.bundle, &name) {
Ok(body_file) => { body_files.push(body_file); },
Err(e) => { error!(LOG_LABEL, "open body_file failed, err is {:?}", e); },
}
}
let file_count = files.len();
let mut task = RequestTask {
conf,
uid,
task_id: info.common_data.task_id,
ctime: info.common_data.ctime,
files: Files(UnsafeCell::new(
files.into_iter().map(|f| YlongFile::new(f)).collect(),
)),
body_files: BodyFiles(UnsafeCell::new(
body_files.into_iter().map(|f| Some(YlongFile::new(f))).collect(),
)),
mime_type: Mutex::new(info.mime_type),
progress: Mutex::new(info.progress.clone()),
tries: AtomicU32::new(info.common_data.tries),
status: Mutex::new(TaskStatus {
waitting_network_time: None,
mtime: get_current_timestamp(),
state: State::from(info.progress.common_data.state),
reason: Reason::from(info.common_data.reason),
}),
retry: AtomicBool::new(info.common_data.retry),
get_file_info: AtomicBool::new(false),
retry_for_request: AtomicBool::new(false),
retry_for_speed: AtomicBool::new(false),
code: Mutex::new(vec![Reason::Default; file_count]),
background_notify_time: AtomicU64::new(get_current_timestamp()),
file_total_size: AtomicI64::new(-1),
resume: AtomicBool::new(false),
seek_flag: AtomicBool::new(false),
range_request: AtomicBool::new(false),
range_response: AtomicBool::new(false),
restored: AtomicBool::new(true),
skip_bytes: AtomicU64::new(0),
upload_counts: AtomicU32::new(progress_index as u32),
client: None,
};
task.client = task.build_client();
match action {
Action::UPLOAD =>
task.file_total_size.store(task.get_upload_file_total_size() as i64, Ordering::SeqCst),
Action::DOWNLOAD =>
task.file_total_size.store(info.progress.sizes[progress_index] as i64, Ordering::SeqCst),
_ => {}
}
task
}
pub fn build_notify_data(&self) -> NotifyData {
let mut vec = Vec::new();
let size = self.conf.file_specs.len();
@ -581,7 +657,9 @@ impl RequestTask {
match len {
Ok(v) => {
let mut guard = self.progress.lock().unwrap();
guard.sizes[0] = v;
if !self.restored.load(Ordering::SeqCst) {
guard.sizes[0] = v;
}
self.file_total_size.store(v, Ordering::SeqCst);
debug!(LOG_LABEL, "the download task content-length is {}", @public(v));
}
@ -827,9 +905,7 @@ impl RequestTask {
if state == State::WAITING {
self.record_waitting_network_time();
}
if self.conf.version == Version::API10 {
self.record_task_info();
}
self.record_task_info();
self.state_change_notify(state);
true
}
@ -925,6 +1001,7 @@ impl RequestTask {
token: self.conf.token.clone(),
form_items: self.conf.form_items.clone(),
file_specs: self.conf.file_specs.clone(),
body_file_names: self.conf.body_file_names.clone(),
title: self.conf.title.clone(),
description: self.conf.description.clone(),
mime_type: {

View File

@ -13,12 +13,14 @@
* limitations under the License.
*/
use super::{enumration::*, form_item::*};
use super::{c_string_wrapper::*, enumration::*, form_item::*, utils::*, request_binding::*};
use std::collections::HashMap;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct CommonTaskConfig {
pub task_id: u32,
pub uid: u64,
pub action: Action,
pub mode: Mode,
pub cover: bool,
@ -49,5 +51,153 @@ pub struct TaskConfig {
pub version: Version,
pub form_items: Vec<FormItem>,
pub file_specs: Vec<FileSpec>,
pub body_file_names: Vec<String>,
pub common_data: CommonTaskConfig,
}
#[repr(C)]
pub struct CommonCTaskConfig {
pub task_id: u32,
pub uid: u64,
pub action: u8,
pub mode: u8,
pub cover: bool,
pub network: u8,
pub metered: bool,
pub roaming: bool,
pub retry: bool,
pub redirect: bool,
pub index: u32,
pub begins: u64,
pub ends: i64,
pub gauge: bool,
pub precise: bool,
pub background: bool,
}
#[repr(C)]
pub struct CTaskConfig {
pub bundle: CStringWrapper,
pub url: CStringWrapper,
pub title: CStringWrapper,
pub description: CStringWrapper,
pub method: CStringWrapper,
pub headers: CStringWrapper,
pub data: CStringWrapper,
pub token: CStringWrapper,
pub extras: CStringWrapper,
pub version: u8,
pub form_items_ptr: *const CFormItem,
pub form_items_len: u32,
pub file_specs_ptr: *const CFileSpec,
pub file_specs_len: u32,
pub body_file_names_ptr: *const CStringWrapper,
pub body_file_names_len: u32,
pub common_data: CommonCTaskConfig,
}
impl TaskConfig {
fn build_vec<A, B, C>(ptr: *const A, len: usize, func: C) -> Vec<B> where C: Fn(&A) -> B,
{
if ptr.is_null() || len == 0 {
return Vec::<B>::new();
}
let slice = unsafe { std::slice::from_raw_parts(ptr, len) };
slice.iter().map(|x| func(x)).collect()
}
pub 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(|x| CStringWrapper::from(x)).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() as *const CFormItem,
form_items_len: form_items.len() as u32,
file_specs_ptr: file_specs.as_ptr() as *const CFileSpec,
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,
background: self.common_data.background,
},
}
}
pub 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: Self::build_vec(
c_struct.form_items_ptr,
c_struct.form_items_len as usize,
FormItem::from_c_struct,
),
file_specs: Self::build_vec(
c_struct.file_specs_ptr,
c_struct.file_specs_len as usize,
FileSpec::from_c_struct,
),
body_file_names: Self::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,
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
}
}

View File

@ -23,6 +23,7 @@ pub struct TaskInfo {
pub token: String,
pub form_items: Vec<FormItem>,
pub file_specs: Vec<FileSpec>,
pub body_file_names: Vec<String>,
pub title: String,
pub description: String,
pub mime_type: String,
@ -101,6 +102,8 @@ pub struct CTaskInfo {
pub form_items_len: u32,
pub file_specs_ptr: *const CFileSpec,
pub file_specs_len: u32,
pub body_file_names_ptr: *const CStringWrapper,
pub body_file_names_len: u32,
pub title: CStringWrapper,
pub description: CStringWrapper,
pub mime_type: CStringWrapper,
@ -113,6 +116,7 @@ pub struct CTaskInfo {
pub struct InfoSet {
pub form_items: Vec<CFormItem>,
pub file_specs: Vec<CFileSpec>,
pub body_file_names: Vec<CStringWrapper>,
pub sizes: String,
pub processed: String,
pub extras: String,
@ -124,6 +128,7 @@ impl TaskInfo {
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(),
body_file_names: self.body_file_names.iter().map(|x| CStringWrapper::from(x)).collect(),
sizes: format!("{:?}", self.progress.sizes),
processed: format!("{:?}", self.progress.processed),
extras: hashmap_to_string(&self.extras),
@ -156,6 +161,8 @@ impl TaskInfo {
form_items_len: info.form_items.len() as u32,
file_specs_ptr: info.file_specs.as_ptr() as *const CFileSpec,
file_specs_len: info.file_specs.len() as u32,
body_file_names_ptr: info.body_file_names.as_ptr() as *const CStringWrapper,
body_file_names_len: info.body_file_names.len() as u32,
title: CStringWrapper::from(&self.title),
description: CStringWrapper::from(&self.description),
mime_type: CStringWrapper::from(&self.mime_type),
@ -184,6 +191,11 @@ impl TaskInfo {
c_struct.file_specs_len as usize,
FileSpec::from_c_struct,
),
body_file_names: Self::build_vec(
c_struct.body_file_names_ptr,
c_struct.body_file_names_len as usize,
CStringWrapper::to_string,
),
title: c_struct.title.to_string(),
description: c_struct.description.to_string(),
mime_type: c_struct.mime_type.to_string(),
@ -197,6 +209,7 @@ impl TaskInfo {
};
unsafe { DeleteCFormItem(c_struct.form_items_ptr) };
unsafe { DeleteCFileSpec(c_struct.file_specs_ptr) };
unsafe { DeleteCStringPtr(c_struct.body_file_names_ptr) };
unsafe { DeleteCEachFileStatus(c_struct.each_file_status_ptr) };
task_info
}

View File

@ -36,6 +36,7 @@ static MILLISECONDS_IN_ONE_MONTH: u64 = 30 * 24 * 60 * 60 * 1000;
static MILLISECONDS_IN_ONE_SECONDS: u64 = 1000;
static REQUEST_SERVICE_ID: i32 = 3706;
static WAITTING_RETRY_INTERVAL: u64 = 10;
static WAITTING_RESTORE_INTERVAL: u64 = 7;
static DUMP_INTERVAL: u64 = 5 * 60;
type AppTask = HashMap<u32, Arc<RequestTask>>;
@ -48,6 +49,7 @@ pub struct TaskManager {
pub front_app_uid: Option<u64>,
pub front_notify_time: u64,
pub unloading: AtomicBool,
pub restoring: AtomicBool,
pub api10_background_task_count: AtomicU32,
pub recording_rdb_num: AtomicU32,
task_handles: Mutex<HashMap<u32, JoinHandle<()>>>,
@ -107,6 +109,7 @@ impl TaskManager {
front_app_uid: None,
front_notify_time: get_current_timestamp(),
unloading: AtomicBool::new(false),
restoring: AtomicBool::new(false),
api10_background_task_count: AtomicU32::new(0),
recording_rdb_num: AtomicU32::new(0),
task_handles: Mutex::new(HashMap::<u32, JoinHandle<()>>::new()),
@ -733,6 +736,97 @@ impl TaskManager {
}
vec
}
pub fn network_check_unload_sa(&self, guard: &MutexGuard<HashMap<u64, AppTask>>) -> bool {
let mut need_unload = false;
for (_, app_task) in guard.iter() {
for (_, task) in app_task.iter() {
let state = task.status.lock().unwrap().state;
if state == State::COMPLETED || state == State::FAILED
|| state == State::REMOVED || state == State::STOPPED {
need_unload = true;
} else if (state == State::WAITING || state == State::PAUSED)
&& (!task.is_satisfied_configuration() || unsafe { !IsOnline() }) {
need_unload = true;
} else {
return false;
}
}
}
return need_unload;
}
pub fn record_all_task_config(&self, guard: &MutexGuard<HashMap<u64, AppTask>>) {
debug!(LOG_LABEL, "record all task config into database");
self.recording_rdb_num.fetch_add(1, Ordering::SeqCst);
for (_, app_task) in guard.iter() {
for (_, task) in app_task.iter() {
if unsafe { HasTaskConfigRecord(task.task_id) } {
continue;
}
let state = task.status.lock().unwrap().state;
if state != State::WAITING && state != State::PAUSED {
continue;
}
let task_config = task.conf.as_ref().clone();
let c_task_config = task_config.to_c_struct(task.task_id, task.uid);
let ret = unsafe { RecordRequestTaskConfig(&c_task_config) };
info!(LOG_LABEL, "insert taskConfig DB ret is {}", @public(ret));
}
}
self.recording_rdb_num.fetch_sub(1, Ordering::SeqCst);
}
pub fn query_all_task_config(&self) -> Option<Vec<Arc<TaskConfig>>> {
debug!(LOG_LABEL, "query all task config in database");
let mut task_config_list: Vec<Arc<TaskConfig>> = Vec::new();
let c_config_list_len = unsafe { QueryTaskConfigLen() };
if c_config_list_len <= 0 {
debug!(LOG_LABEL, "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(Arc::new(task_config));
unsafe { DeleteCTaskConfig(*c_task_config) };
}
unsafe { DeleteCTaskConfigs(c_task_config_list) };
Some(task_config_list)
}
pub fn restore_task(&mut self, task: Arc<RequestTask>) {
if task.conf.common_data.mode == Mode::FRONTEND {
self.global_front_task = Some(task);
return;
}
if task.conf.version == Version::API10 {
self.api10_background_task_count.fetch_add(1, Ordering::SeqCst);
}
let mut guard = self.task_map.lock().unwrap();
let uid = task.uid;
let task_id = task.task_id;
if self.get_task(uid, task_id, &guard).is_some() {
return;
}
let app_task = guard.get_mut(&uid);
match app_task {
Some(map) => {
map.insert(task_id, task);
debug!(LOG_LABEL, "restore task into exist app_map success");
}
None => {
let mut app_task = AppTask::new();
app_task.insert(task_id, task);
guard.insert(uid, app_task);
debug!(LOG_LABEL, "restore task into new app_map success");
}
}
}
}
pub async fn unload_sa() {
@ -744,12 +838,16 @@ pub async fn unload_sa() {
Ok(guard) => {
let total_task_count = task_manager.get_total_task_count(&guard);
let recording_rdb_num = task_manager.recording_rdb_num.load(Ordering::SeqCst);
if total_task_count != 0 || recording_rdb_num != 0 {
let only_network_unsat = task_manager.network_check_unload_sa(&guard);
if (total_task_count != 0 && !only_network_unsat) || recording_rdb_num != 0 {
info!(LOG_LABEL, "total_task_count is {}, recording_rdb_num is {}",
@public(total_task_count), @public(recording_rdb_num));
continue;
}
task_manager.unloading.store(true, Ordering::SeqCst);
if total_task_count != 0 {
task_manager.record_all_task_config(&guard);
}
info!(LOG_LABEL, "unload SA");
let samgr_proxy = get_systemability_manager();
let res = samgr_proxy.unload_systemability(REQUEST_SERVICE_ID);
@ -808,6 +906,37 @@ async fn remove_task_from_map(task: Arc<RequestTask>) {
task_manager.process_waitting_task(remove_task.uid, remove_task.conf.version, &guard);
}
pub async fn restore_all_tasks() {
let task_manager = TaskManager::get_instance();
if task_manager.restoring.load(Ordering::SeqCst) {
return;
}
task_manager.restoring.store(true, Ordering::SeqCst);
if let Some(config_list) = task_manager.query_all_task_config() {
info!(LOG_LABEL, "RSA query task config list len: {} in database", @public(config_list.len()));
for config in config_list.iter() {
debug!(LOG_LABEL, "RSA query task config is {:?}", @public(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) = task_manager.touch(uid, task_id, token) {
let state = State::from(task_info.progress.common_data.state);
if state != State::WAITING && state != State::PAUSED {
continue;
}
let request_task = RequestTask::restore_task(config.clone(), task_info);
let task = Arc::new(request_task);
task_manager.restore_task(task.clone());
if unsafe { IsOnline() } {
resume_waiting_task(task.clone(), uid, WAITTING_RESTORE_INTERVAL);
}
}
unsafe { CleanTaskConfigTable(task_id, uid) };
}
}
task_manager.restoring.store(false, Ordering::SeqCst);
}
pub fn monitor_network() {
debug!(LOG_LABEL, "monitor_network");
unsafe {
@ -822,26 +951,29 @@ extern "C" fn net_work_change_callback() {
for (uid, app_task) in guard.iter() {
let uid = *uid;
for (_, task) in app_task.iter() {
let task = task.clone();
let state = task.status.lock().unwrap().state;
if unsafe { IsOnline() } {
if state == State::WAITING && task.is_satisfied_configuration() {
info!(LOG_LABEL, "Begin try resume task as network condition resume");
task.resume.store(true, Ordering::SeqCst);
ylong_runtime::spawn(async move {
sleep(Duration::from_secs(WAITTING_RETRY_INTERVAL)).await;
let manager = TaskManager::get_instance();
let guard = manager.task_map.lock().unwrap();
let notify_data = task.build_notify_data();
TaskManager::get_instance().front_notify("resume".into(), &notify_data);
manager.start_inner(uid, task.clone(), guard);
});
}
resume_waiting_task(task.clone(), uid, WAITTING_RETRY_INTERVAL);
}
}
}
}
pub fn resume_waiting_task(task: Arc<RequestTask>, uid: u64, interval: u64) {
let state = task.status.lock().unwrap().state;
if state == State::WAITING && task.is_satisfied_configuration() {
info!(LOG_LABEL, "Begin try resume task as network condition resume");
task.resume.store(true, Ordering::SeqCst);
ylong_runtime::spawn(async move {
sleep(Duration::from_secs(interval)).await;
let manager = TaskManager::get_instance();
let guard = manager.task_map.lock().unwrap();
let notify_data = task.build_notify_data();
TaskManager::get_instance().front_notify("resume".into(), &notify_data);
manager.start_inner(uid, task.clone(), guard);
});
}
}
pub fn monitor_app_state() {
debug!(LOG_LABEL, "monitor_app_state");
unsafe {