From 29fe221e6073230c109b583c32dbed66bd6a7bd2 Mon Sep 17 00:00:00 2001 From: liyi216 Date: Mon, 24 Jan 2022 00:54:15 +0800 Subject: [PATCH] add cgroup sched to rss Signed-off-by: liyi216 --- cgroup_sched/README.md | 88 ++++++ cgroup_sched/README_zh.md | 89 ++++++ cgroup_sched/cgroup_sched.gni | 22 ++ .../common/include/cgroup_sched_common.h | 71 +++++ .../common/include/cgroup_sched_log.h | 37 +++ .../continuous_task_dummy.h | 91 ++++++ cgroup_sched/framework/BUILD.gn | 56 ++++ cgroup_sched/framework/process_group/BUILD.gn | 39 +++ .../process_group/include/cgroup_action.h | 47 +++ .../process_group/include/cgroup_controller.h | 59 ++++ .../process_group/include/cgroup_map.h | 55 ++++ .../process_group/include/process_group_log.h | 46 +++ .../include/process_group_util.h | 41 +++ .../process_group/include/sched_policy.h | 100 +++++++ .../process_group/src/cgroup_action.cpp | 116 ++++++++ .../process_group/src/cgroup_controller.cpp | 160 +++++++++++ .../process_group/src/cgroup_map.cpp | 129 +++++++++ .../process_group/src/process_group_util.cpp | 119 ++++++++ .../process_group/src/sched_policy.cpp | 99 +++++++ .../sched_controller/app_state_observer.cpp | 129 +++++++++ .../sched_controller/cgroup_adjuster.cpp | 139 +++++++++ .../sched_controller/cgroup_event_handler.cpp | 270 ++++++++++++++++++ .../continuous_task_observer.cpp | 78 +++++ .../include/app_state_observer.h | 61 ++++ .../include/cgroup_adjuster.h | 56 ++++ .../include/cgroup_event_handler.h | 60 ++++ .../include/continuous_task_observer.h | 56 ++++ .../include/sched_controller.h | 87 ++++++ .../sched_controller/include/supervisor.h | 127 ++++++++ .../include/transient_task_observer.h | 54 ++++ .../include/window_state_observer.h | 40 +++ .../sched_controller/sched_controller.cpp | 224 +++++++++++++++ .../framework/sched_controller/supervisor.cpp | 117 ++++++++ .../transient_task_observer.cpp | 64 +++++ .../window_state_observer.cpp | 47 +++ .../framework/utils/include/ressched_utils.h | 55 ++++ .../framework/utils/ressched_utils.cpp | 61 ++++ .../innerkits/include/cgroup_sched.h | 31 ++ cgroup_sched/profiles/BUILD.gn | 28 ++ .../profiles/others/cgroup_action_config.json | 26 ++ .../profiles/rk3658/cgroup_action_config.json | 26 ++ ressched/bundle.json | 8 +- .../etc/init/resource_schedule_service.cfg | 1 + .../ressched_client/include/res_type.h | 16 ++ .../ressched_client/src/res_sched_client.cpp | 8 +- ressched/services/BUILD.gn | 3 + .../src/res_sched_service_ability.cpp | 5 +- 47 files changed, 3337 insertions(+), 4 deletions(-) create mode 100644 cgroup_sched/README.md create mode 100644 cgroup_sched/README_zh.md create mode 100644 cgroup_sched/cgroup_sched.gni create mode 100644 cgroup_sched/common/include/cgroup_sched_common.h create mode 100644 cgroup_sched/common/include/cgroup_sched_log.h create mode 100644 cgroup_sched/dummy_adaption/background_task_mgr/continuous_task_dummy.h create mode 100644 cgroup_sched/framework/BUILD.gn create mode 100644 cgroup_sched/framework/process_group/BUILD.gn create mode 100644 cgroup_sched/framework/process_group/include/cgroup_action.h create mode 100644 cgroup_sched/framework/process_group/include/cgroup_controller.h create mode 100644 cgroup_sched/framework/process_group/include/cgroup_map.h create mode 100644 cgroup_sched/framework/process_group/include/process_group_log.h create mode 100644 cgroup_sched/framework/process_group/include/process_group_util.h create mode 100644 cgroup_sched/framework/process_group/include/sched_policy.h create mode 100644 cgroup_sched/framework/process_group/src/cgroup_action.cpp create mode 100644 cgroup_sched/framework/process_group/src/cgroup_controller.cpp create mode 100644 cgroup_sched/framework/process_group/src/cgroup_map.cpp create mode 100644 cgroup_sched/framework/process_group/src/process_group_util.cpp create mode 100644 cgroup_sched/framework/process_group/src/sched_policy.cpp create mode 100644 cgroup_sched/framework/sched_controller/app_state_observer.cpp create mode 100644 cgroup_sched/framework/sched_controller/cgroup_adjuster.cpp create mode 100644 cgroup_sched/framework/sched_controller/cgroup_event_handler.cpp create mode 100644 cgroup_sched/framework/sched_controller/continuous_task_observer.cpp create mode 100644 cgroup_sched/framework/sched_controller/include/app_state_observer.h create mode 100644 cgroup_sched/framework/sched_controller/include/cgroup_adjuster.h create mode 100644 cgroup_sched/framework/sched_controller/include/cgroup_event_handler.h create mode 100644 cgroup_sched/framework/sched_controller/include/continuous_task_observer.h create mode 100644 cgroup_sched/framework/sched_controller/include/sched_controller.h create mode 100644 cgroup_sched/framework/sched_controller/include/supervisor.h create mode 100644 cgroup_sched/framework/sched_controller/include/transient_task_observer.h create mode 100644 cgroup_sched/framework/sched_controller/include/window_state_observer.h create mode 100644 cgroup_sched/framework/sched_controller/sched_controller.cpp create mode 100644 cgroup_sched/framework/sched_controller/supervisor.cpp create mode 100644 cgroup_sched/framework/sched_controller/transient_task_observer.cpp create mode 100644 cgroup_sched/framework/sched_controller/window_state_observer.cpp create mode 100644 cgroup_sched/framework/utils/include/ressched_utils.h create mode 100644 cgroup_sched/framework/utils/ressched_utils.cpp create mode 100644 cgroup_sched/interfaces/innerkits/include/cgroup_sched.h create mode 100644 cgroup_sched/profiles/BUILD.gn create mode 100644 cgroup_sched/profiles/others/cgroup_action_config.json create mode 100644 cgroup_sched/profiles/rk3658/cgroup_action_config.json diff --git a/cgroup_sched/README.md b/cgroup_sched/README.md new file mode 100644 index 00000000..b9de1169 --- /dev/null +++ b/cgroup_sched/README.md @@ -0,0 +1,88 @@ +# Cgroup Schedule + +- [Cgroup Schedule](#cgroup-schedule) + - [Introduction](#introduction) + - [Structure](#structure) + - [Cgroup Schedule Policy](#cgroup-schedule-policy) + - [Basic Policy](#basic-policy) + - [Policy Configuration](#policy-configuration) + - [Restrictions](#restrictions) + - [Repositories Involved](#repositories-involved) + +## Introduction + +In resource schedule subsystem, the module of cgroup schedule decides the group schedule policy of each process by analyzing application state, window status and background task status. And with proper configuration, it can bind each process to certain cgroup node. These schedule policies can be used to gain better performance. And this module forward different kinds of events to plugin manager and then be distributed to subscribers. + +## Structure + +``` +├── common +│   └── include +├── framework +│   ├── process_group +│   ├── sched_controller +│   └── utils +│   ├── include +│   │   └── ressched_utils.h +│   └── ressched_utils.cpp +├── interfaces +│   └── innerkits +└── profiles +``` + +## Cgroup Schedule Policy + +### Basic Policy + +| Scene | Schedule policy | +|----------|-------| +| Currently focused oreground application and processes with same uid | top_app | +| Foreground visible processes, include unfocused window process in split mode, float window process, foundation process | foreground | +| system level daemon processes. Assgin system schedule policy to them when started, | system | +| Background application and processes with same uid | background | +| kernel processes, most native processes and others have not mensioned | root | + +### Policy Configuration + +Each schedule policy is configured in a json file, and is bound to different cgroup. +``` + "Cgroups": [ + { + "controller": "cpuctl", + "path": "/dev/cpuctl", + "sched_policy": { + "sp_default": "", + "sp_background": "background", + "sp_foreground": "foreground", + "sp_system": "system", + "sp_top_app": "top-app" + } + } + ] +``` + +### Restrictions + +Configuration file: cgroup_action_config.json +Every schedule policy defined should be configured. + +Introduction to each config item: + +| Item | Description | +|--------|--------| +|controller|cgroup controller: cpuset, cpuctl, blkio etc.| +|path|Absolute path of current cgroup| +|sched_policy|Binding between each schedule policy and cgroup| +|sp_xx|Different kinds of schedule policy| + +## Repositories Involved + +Resource Schedule Subsystem + +**resource\_schedule\_service** + +safwk + +appexecfwk_standard + +ipc diff --git a/cgroup_sched/README_zh.md b/cgroup_sched/README_zh.md new file mode 100644 index 00000000..20610030 --- /dev/null +++ b/cgroup_sched/README_zh.md @@ -0,0 +1,89 @@ +# 智能分组 + +- [智能分组](#智能分组) + - [简介](#简介) + - [目录](#目录) + - [分组策略](#分组策略) + - [基础分组策略](#基础分组策略) + - [策略配置](#策略配置) + - [配置约束](#配置约束) + - [相关仓](#相关仓) + +- [相关仓](#相关仓) + +## 简介 + +在资源调度子系统中,智能分组模块通过系统内应用前后台切换、用户焦点输入、后台任务的执行状态,决策进程的分组调度策略,并支持通过配置将调度策略映射到不同的CGROUP分组,为系统的性能、功耗均衡调度提供决策依据。同时该模块向ressched框架转发应用状态、焦点状态、后台任务状态等系统事件,供插件订阅。 + +## 目录 + +``` +├── common +│   └── include # 公共头文件 +├── framework # 主体代码 +│   ├── process_group # 分组设置接口 +│   ├── sched_controller # 分组计算 +│   └── utils # RMS数据转发适配接口 +│   ├── include +│   │   └── ressched_utils.h +│   └── ressched_utils.cpp +├── interfaces # 供RSS初始化、查询分组接口 +│   └── innerkits +└── profiles +``` + +## 分组策略 + +### 基础分组策略 + +| 场景描述 | 分组策略 | +|----------|-------| +| 前台焦点应用,UID相同的进程 | top_app | +| 前台可见的,包括分屏场景下的非焦点应用进程、悬浮窗对应的进程、foundation进程等 | foreground | +| 一些系统级后台常驻进程,不由分组计算主动设置。在rc/cfg文件中写定,直接写入system分组 | system | +| 退到后台的前一个应用,及其相关的进程 | background | +| OS内核和其他native进程,以及上面没有涉及到的一些进程 | root | + +### 策略配置 + +通过JSON配置文件,对每个分组策略,绑定指定的CGROUP分组。 +``` + "Cgroups": [ + { + "controller": "cpuctl", + "path": "/dev/cpuctl", + "sched_policy": { + "sp_default": "", + "sp_background": "background", + "sp_foreground": "foreground", + "sp_system": "system", + "sp_top_app": "top-app" + } + } + ] +``` + +### 配置约束 + +策略配置路径:cgroup_action_config.json文件; 每个sp_xxx策略都需要配置 + +配置参数说明: + +| 配置项 | 说明 | +|--------|--------| +|controller|当前配置项对应的cgroup分组控制器| +|path|cgroup分组对应的路径| +|sched_policy|不同分组调度策略对应到的具体分组| +|sp_xx|不同分组调度策略标识| + +## 相关仓 + +资源调度子系统 + +**resource\_schedule\_service** + +safwk + +appexecfwk_standard + +ipc diff --git a/cgroup_sched/cgroup_sched.gni b/cgroup_sched/cgroup_sched.gni new file mode 100644 index 00000000..853d9f8a --- /dev/null +++ b/cgroup_sched/cgroup_sched.gni @@ -0,0 +1,22 @@ +# Copyright (C) 2021 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. + +cgroup_sched_path = "//foundation/resourceschedule/resource_schedule_service/cgroup_sched" + +cgroup_sched_framework = "${cgroup_sched_path}/framework" + +cgroup_sched_common = "${cgroup_sched_path}/common" + +cgroup_sched_dummy = "${cgroup_sched_path}/dummy_adaption" + +cgroup_sched_interfaces = "${cgroup_sched_path}/interfaces" \ No newline at end of file diff --git a/cgroup_sched/common/include/cgroup_sched_common.h b/cgroup_sched/common/include/cgroup_sched_common.h new file mode 100644 index 00000000..f3c7be13 --- /dev/null +++ b/cgroup_sched/common/include/cgroup_sched_common.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021 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 CGROUP_SCHED_COMMON_H +#define CGROUP_SCHED_COMMON_H + +#include +#include +#include + +#include "cgroup_sched_log.h" + +namespace OHOS { +namespace ResourceSchedule { +#ifndef VALUE_INT +#define VALUE_INT(t) (static_cast(t)) +#endif + +using Clock = std::chrono::high_resolution_clock; +using MilliSecondsType = std::chrono::duration; + +class ChronoScope { +public: + ChronoScope(const std::string outmsg) : outmsg_(outmsg) + { + out_ = nullptr; + t1 = Clock::now(); + } + + ChronoScope(const std::string outmsg, double* out) : outmsg_(outmsg), out_(out) + { + t1 = Clock::now(); + } + + ~ChronoScope() + { + Clock::time_point t2 = Clock::now(); + MilliSecondsType time_span = std::chrono::duration_cast(t2 - t1); + HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_RMS, "ChronoScope"}; + CGS_LOGI("[%{public}s] cost %{public}lf milliseconds.", outmsg_.c_str(), time_span.count()); + if (out_ != nullptr){ + *out_ = time_span.count(); + } + } +private: + ChronoScope(const ChronoScope&) = delete; + ChronoScope& operator=(const ChronoScope &) = delete; + ChronoScope(ChronoScope&&) = delete; + ChronoScope& operator=(ChronoScope&&) = delete; + + std::string outmsg_; + double* out_; + Clock::time_point t1; +}; + +} // namespace ResourceSchedule +} // namespace OHOS + +#endif //CGROUP_SCHED_COMMON_H diff --git a/cgroup_sched/common/include/cgroup_sched_log.h b/cgroup_sched/common/include/cgroup_sched_log.h new file mode 100644 index 00000000..108beca1 --- /dev/null +++ b/cgroup_sched/common/include/cgroup_sched_log.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 CGROUP_SCHED_LOG_H +#define CGROUP_SCHED_LOG_H + +#include +#include +#include "hilog/log.h" + +namespace OHOS { +namespace ResourceSchedule { + +#define LOG_TAG_DOMAIN_ID_RMS 0xD001700 + +#define CGS_LOGF(...) (void)OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, __VA_ARGS__) +#define CGS_LOGE(...) (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, __VA_ARGS__) +#define CGS_LOGW(...) (void)OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, __VA_ARGS__) +#define CGS_LOGI(...) (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, __VA_ARGS__) +#define CGS_LOGD(...) (void)OHOS::HiviewDFX::HiLog::Debug(LOG_LABEL, __VA_ARGS__) + +} // namespace ResourceSchedule +} // namespace OHOS + +#endif //CGROUP_SCHED_LOG_H diff --git a/cgroup_sched/dummy_adaption/background_task_mgr/continuous_task_dummy.h b/cgroup_sched/dummy_adaption/background_task_mgr/continuous_task_dummy.h new file mode 100644 index 00000000..cddcb232 --- /dev/null +++ b/cgroup_sched/dummy_adaption/background_task_mgr/continuous_task_dummy.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2021 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 CONTINUOUS_TASK_DUMMY_H +#define CONTINUOUS_TASK_DUMMY_H + +#include "parcel.h" + +namespace OHOS { +namespace BackgroundTaskMgr { +class ContinuousTaskEventData : public Parcelable { +public: + enum : int32_t { + LONGTIME_TASK_START = 0, + LONGTIME_TASK_CANCEL + }; + + ContinuousTaskEventData(); + ContinuousTaskEventData(int32_t typeId, uid_t creatorUid, pid_t creatorPid, std::string abilityName); + virtual ~ContinuousTaskEventData(); + + int32_t GetTypeId() + { + return typeId_; + } + uid_t GetCreatorUid() + { + return creatorUid_; + } + pid_t GetCreatorPid() + { + return creatorPid_; + } + std::string GetAbilityName() + { + return abilityName_; + } + bool Marshalling(Parcel &parcel) const; + static ContinuousTaskEventData *Unmarshalling(Parcel &parcel); + +private: + bool ReadFromParcel(Parcel &parcel); + + int32_t typeId_; + uid_t creatorUid_; + pid_t creatorPid_; + std::string abilityName_; +}; + +class ContinuousTaskConstant final { +public: + enum class SubscribeResult : int32_t { + SUCCESS = 0, + FAILED + }; +}; + +class ContinuousTaskEventSubscriber { +public: + ContinuousTaskEventSubscriber() {}; + virtual ~ContinuousTaskEventSubscriber() {}; + + virtual void OnSubscribeResult(ContinuousTaskConstant::SubscribeResult result); + virtual void OnUnsubscribeResult(ContinuousTaskConstant::SubscribeResult result); + virtual void OnContinuousTaskStart(const std::shared_ptr &continuousTaskEventData); + virtual void OnContinuousTaskCancel(const std::shared_ptr &continuousTaskEventData); + virtual void OnDied(); +}; + +class BackgroundTaskMgrHelper_ { +public: + static bool RequestSubscribe(const ContinuousTaskEventSubscriber &subscriber) {return true;}; + static bool RequestUnsubscribe(const ContinuousTaskEventSubscriber &subscriber) {return true;}; +}; + +} +} + +#endif // CONTINUOUS_TASK_DUMMY_H \ No newline at end of file diff --git a/cgroup_sched/framework/BUILD.gn b/cgroup_sched/framework/BUILD.gn new file mode 100644 index 00000000..2c3a8fec --- /dev/null +++ b/cgroup_sched/framework/BUILD.gn @@ -0,0 +1,56 @@ +# Copyright (c) 2022 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("//build/ohos.gni") +import("//foundation/resourceschedule/resource_schedule_service/cgroup_sched/cgroup_sched.gni") + +ohos_shared_library("cgroup_sched") { + sources = [ + "sched_controller/cgroup_adjuster.cpp", + "sched_controller/sched_controller.cpp", + "sched_controller/cgroup_event_handler.cpp", + "sched_controller/supervisor.cpp", + "sched_controller/app_state_observer.cpp", + "sched_controller/continuous_task_observer.cpp", + "sched_controller/transient_task_observer.cpp", + "sched_controller/window_state_observer.cpp", + "utils/ressched_utils.cpp", + ] + include_dirs = [ + "../../ressched/interfaces/innerkits/ressched_client/include", + "../common/include", + "./sched_controller/include", + "./utils/include", + ] + deps = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//foundation/appexecfwk/standard/common:libappexecfwk_common", + "//foundation/resourceschedule/background_task_mgr/interfaces/innerkits:bgtaskmgr_innerkits", + "//foundation/resourceschedule/background_task_mgr/frameworks:bgtaskmgr_fwk", + "//utils/native/base:utils", + "//foundation/windowmanager/wmserver:libwms", + "./process_group:libprocess_group", + ] + external_deps = [ + "ability_runtime:app_manager", + "appexecfwk_standard:appexecfwk_base", + "appexecfwk_standard:appexecfwk_core", + "appexecfwk_standard:libeventhandler", + "safwk:system_ability_fwk", + "samgr_standard:samgr_proxy", + "window_manager:libwm", + ] + + part_name = "resource_schedule_service" + subsystem_name = "resourceschedule" +} diff --git a/cgroup_sched/framework/process_group/BUILD.gn b/cgroup_sched/framework/process_group/BUILD.gn new file mode 100644 index 00000000..8aefb613 --- /dev/null +++ b/cgroup_sched/framework/process_group/BUILD.gn @@ -0,0 +1,39 @@ +# Copyright (c) 2021 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("//build/ohos.gni") + +config("libprocess_group_config") { + include_dirs = [ "./include" ] +} + +ohos_shared_library("libprocess_group") { + sources = [ + "./src/cgroup_controller.cpp", + "./src/cgroup_map.cpp", + "./src/process_group_util.cpp", + "./src/sched_policy.cpp", + "./src/cgroup_action.cpp", + ] + include_dirs = [ + "./include" + ] + deps = [ + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//utils/native/base:utils", + "//third_party/jsoncpp:jsoncpp", + ] + public_configs = [ ":libprocess_group_config" ] + part_name = "resource_schedule_service" + subsystem_name = "resourceschedule" +} diff --git a/cgroup_sched/framework/process_group/include/cgroup_action.h b/cgroup_sched/framework/process_group/include/cgroup_action.h new file mode 100644 index 00000000..ce4e610d --- /dev/null +++ b/cgroup_sched/framework/process_group/include/cgroup_action.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_CGROUP_ACTION_H +#define OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_CGROUP_ACTION_H + +#include "cgroup_map.h" + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +class CgroupAction{ +public: + static CgroupAction& GetInstance(); + + CgroupAction(const CgroupAction& cgroupAction) = delete; + CgroupAction& operator= (const CgroupAction& cgroupAction) = delete; + ~CgroupAction() = default; + bool SetThreadSchedPolicy(int tid, SchedPolicy policy); + bool SetThreadGroupSchedPolicy(int tid, SchedPolicy policy); + int GetSchedPolicy(int tid, SchedPolicy* policy); + +private: + CgroupAction() = default; + bool loadConfigFile(); + bool IsEnabled(); + static bool ParseConfigFileToJsonObj(Json::Value& jsonObjRoot); +}; + +} // namepsace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS +#endif + diff --git a/cgroup_sched/framework/process_group/include/cgroup_controller.h b/cgroup_sched/framework/process_group/include/cgroup_controller.h new file mode 100644 index 00000000..4cb018e5 --- /dev/null +++ b/cgroup_sched/framework/process_group/include/cgroup_controller.h @@ -0,0 +1,59 @@ + +/* + * Copyright (c) 2021 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 OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_CGROUP_CONTROLLER_H +#define OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_CGROUP_CONTROLLER_H + +#include +#include +#include "sched_policy.h" + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +class CgroupController { +public: + CgroupController(const std::string& name, const std::string& path); + ~CgroupController(); + + CgroupController(const CgroupController& controller) = delete; + CgroupController& operator=(const CgroupController& controller) = delete; + CgroupController(CgroupController&& controller); + CgroupController& operator=(CgroupController&& controller); + + std::string GetName() { return path_; } + std::string GetPath() { return name_; } + bool IsEnabled(); + bool SetThreadSchedPolicy(int tid, SchedPolicy policy, bool isSetThreadGroup); + bool AddSchedPolicy(SchedPolicy policy, const std::string& subgroup); + bool GetTaskGroup(int tid, std::string& group); + +private: + std::string name_; + std::string path_; + std::vector policyToTaskFd_; + std::vector policyToProcFd_; + + bool AddThreadSchedPolicy(SchedPolicy policy, const std::string& subgroup); + bool AddThreadGroupSchedPolicy(SchedPolicy policy, const std::string& subgroup); + static bool AddTidToCgroup(int tid, int fd); +}; + +} // namespace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS +#endif \ No newline at end of file diff --git a/cgroup_sched/framework/process_group/include/cgroup_map.h b/cgroup_sched/framework/process_group/include/cgroup_map.h new file mode 100644 index 00000000..3df7c517 --- /dev/null +++ b/cgroup_sched/framework/process_group/include/cgroup_map.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 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 OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_CGROUP_MAP_H +#define OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_CGROUP_MAP_H + +#include +#include +#include +#include "sched_policy.h" +#include "json/value.h" +#include "cgroup_controller.h" + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +class CgroupMap { +public: + static CgroupMap& GetInstance(); + CgroupMap(const CgroupMap&) = delete; + CgroupMap& operator=(const CgroupMap&) = delete; + ~CgroupMap() = default; + + bool SetThreadSchedPolicy(int tid, SchedPolicy policy, bool isSetThreadGroup); + bool loadConfigFromJsonObj(const Json::Value& jsonObj); + + bool findFristEnableCgroupController(CgroupController** p); + int GetSchedPolicy(int tid, SchedPolicy* policy); + +private: + std::map controllers_; + + CgroupMap() = default; + bool checkCgroupConfig(); + void AddCgroupController(const std::string& name, CgroupController& controller); + static bool CheckCgroupJsonConfig(const Json::Value& cgroupObj); +}; + +} // namespace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS +#endif \ No newline at end of file diff --git a/cgroup_sched/framework/process_group/include/process_group_log.h b/cgroup_sched/framework/process_group/include/process_group_log.h new file mode 100644 index 00000000..f56d7ed7 --- /dev/null +++ b/cgroup_sched/framework/process_group/include/process_group_log.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_LOG_H +#define OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_LOG_H + +#include +#include +#include "hilog/log.h" + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +#define LOG_TAG_PGCGS "pg-cgs" +#define LOG_TAG_DOMAIN_ID_PGCGS 0xD001700 + +static constexpr OHOS::HiviewDFX::HiLogLabel PGCGS_LOG_LABEL = { + LOG_CORE, + LOG_TAG_DOMAIN_ID_PGCGS, + LOG_TAG_PGCGS +}; + +#define PGCGS_LOGF(...) (void)OHOS::HiviewDFX::HiLog::Fatal(PGCGS_LOG_LABEL, __VA_ARGS__) +#define PGCGS_LOGE(...) (void)OHOS::HiviewDFX::HiLog::Error(PGCGS_LOG_LABEL, __VA_ARGS__) +#define PGCGS_LOGW(...) (void)OHOS::HiviewDFX::HiLog::Warn(PGCGS_LOG_LABEL, __VA_ARGS__) +#define PGCGS_LOGI(...) (void)OHOS::HiviewDFX::HiLog::Info(PGCGS_LOG_LABEL, __VA_ARGS__) +#define PGCGS_LOGD(...) (void)OHOS::HiviewDFX::HiLog::Debug(PGCGS_LOG_LABEL, __VA_ARGS__) + +} // namespace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS + +#endif //CGROUP_SCHED_LOG_H diff --git a/cgroup_sched/framework/process_group/include/process_group_util.h b/cgroup_sched/framework/process_group/include/process_group_util.h new file mode 100644 index 00000000..a4d95d1b --- /dev/null +++ b/cgroup_sched/framework/process_group/include/process_group_util.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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 OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_UTIL_H +#define OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_UTIL_H + +#include + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +std::string FormatString(const char* fmt, va_list vararg); + +std::string StringPrintf(const char* fmt, ...); + +bool ReadFileToString(const std::string& fileName, std::string& content); + +bool WriteStringToFile(int fd, const std::string& content); + +bool WriteStringToFile(const std::string& content, const std::string& fileName); + +bool ReadFileToStringForVFS(const std::string& fileName, std::string& content); + +} // namespace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/cgroup_sched/framework/process_group/include/sched_policy.h b/cgroup_sched/framework/process_group/include/sched_policy.h new file mode 100644 index 00000000..95d856a4 --- /dev/null +++ b/cgroup_sched/framework/process_group/include/sched_policy.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021 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 OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_SCHED_POLICY_H +#define OHOS_RESOURCE_SCHEDULE_SERVICE_CGROUP_SCHED_FRAMEWORKS_PROCESS_GROUP_INCLUDE_SCHED_POLICY_H + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +/** + * + * Schedule policy define, keep in sync with + * (1) cgroup_controller.cpp: bool QuerySchedPolicyFullName(const std::string& name, SchedPolicy& policy); + * (2) sched_policy.cpp: const char* GetSchedPolicyShortenedName(SchedPolicy policy); + */ +enum SchedPolicy { + SP_DEFAULT = 0, + SP_BACKGROUND = 1, + SP_FOREGROUND = 2, + SP_SYSTEM = 3, + SP_TOP_APP = 4, + SP_CNT, + SP_MAX = SP_CNT - 1, + SP_SYSTEM_DEFAULT = SP_DEFAULT, +}; + +/** + * Assign all threads in process pid to the cgroup associated with the specified policy. + * On platforms which support getpid(), zero pid means current process. + * Return value: 0 for success, or -errno for error. + * + * @param pid process id. + * @param policy schedule policy. + * @return Return value: 0 for success, or -errno for error. + */ +int SetThreadGroupSchedPolicy(int pid, int policy); + +/** + * Assign thread tid to the cgroup associated with the specified policy. + * On platforms which support gettid(), zero tid means current thread. + * If the thread is a thread group leader, that is it's gettid() == getpid(), + * then the other threads in the same thread group are _not_ affected. + * Return value: 0 for success, or -errno for error. + * + * @param tid thread id. + * @param policy variable to accept return value. + * @return Return value: 0 for success, or -errno for error. + */ +int SetThreadSchedPolicy(int pid, int policy); + +/** + * Return the policy associated with the cgroup of thread tid via policy pointer. + * On platforms which support gettid(), zero tid means current thread. + * Return value: 0 for success, or -1 for error and set errno. + * + * @param tid thread id. + * @param policy a policy pointer. + * @return Return value: 0 for success, or -errno for error. + */ +int GetThreadSchedPolicy(int tid, SchedPolicy* policy); + +/* + * Return a displayable string corresponding to policy: shortened name. + * Return value: NUL-terminated name of unspecified length, nullptr if invalid; + * the caller is responsible for displaying the useful part of the string. + * + * @param policy schedule policy. + * @return Return a displayable string corresponding to policy. + */ +const char* GetSchedPolicyShortenedName(SchedPolicy policy); + +/* + * Return a displayable string corresponding to policy: full name. + * Return value: NUL-terminated name of unspecified length, nullptr if invalid; + * the caller is responsible for displaying the useful part of the string. + * + * @param policy schedule policy. + * @return Return a displayable string corresponding to policy. + */ + +const char* GetSchedPolicyFullName(SchedPolicy policy); + +} // namepsace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS + +#endif diff --git a/cgroup_sched/framework/process_group/src/cgroup_action.cpp b/cgroup_sched/framework/process_group/src/cgroup_action.cpp new file mode 100644 index 00000000..37f7c6f1 --- /dev/null +++ b/cgroup_sched/framework/process_group/src/cgroup_action.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2021 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 "process_group_log.h" +#include "process_group_util.h" +#include "cgroup_map.h" +#include "cgroup_action.h" +#include "sched_policy.h" +#include "json/reader.h" +#include "json/value.h" + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { +namespace { + static constexpr const char* CGROUP_SETTING_CONFIG_FILE = "etc/process_group/cgroup_action_config.json"; +} + +CgroupAction& CgroupAction::GetInstance() +{ + static CgroupAction instance; + return instance; +} + +bool CgroupAction::SetThreadSchedPolicy(int tid, SchedPolicy policy) +{ + if (!IsEnabled()) { + return false; + } + return CgroupMap::GetInstance().SetThreadSchedPolicy(tid, policy, false); +} + +bool CgroupAction::SetThreadGroupSchedPolicy(int tid, SchedPolicy policy) +{ + if (!IsEnabled()) { + return false; + } + return CgroupMap::GetInstance().SetThreadSchedPolicy(tid, policy, true); +} + +bool CgroupAction::loadConfigFile() +{ + PGCGS_LOGI("CgroupAction::loadConfigFile loading config file"); + Json::Value jsonObjRoot; + if (!ParseConfigFileToJsonObj(jsonObjRoot)) { + return false; + } + return CgroupMap::GetInstance().loadConfigFromJsonObj(jsonObjRoot); +} + +bool CgroupAction::IsEnabled() +{ + static bool enable = loadConfigFile(); + return enable; +} + +int CgroupAction::GetSchedPolicy(int tid, SchedPolicy* policy) { + if (!IsEnabled()) { + return -1; + } + std::string subgroup; + CgroupController *controller; + CgroupMap& instance = CgroupMap::GetInstance(); + if (instance.findFristEnableCgroupController(&controller)) { + if (!controller->GetTaskGroup(tid, subgroup)) { + return -1; + } + } + if (subgroup.empty()) { + *policy = SP_DEFAULT; + } else if (subgroup == "foreground") { + *policy = SP_FOREGROUND; + } else if (subgroup == "background") { + *policy = SP_BACKGROUND; + } else if (subgroup == "top-app") { + *policy = SP_TOP_APP; + } else if (subgroup == "system") { + *policy = SP_SYSTEM; + } else { + return -1; + } + return 0; +} + +bool CgroupAction::ParseConfigFileToJsonObj(Json::Value& jsonObjRoot) +{ + std::string jsonString; + if (!ReadFileToString(CGROUP_SETTING_CONFIG_FILE, jsonString)) { + PGCGS_LOGE("ParseConfigFileToJsonObj: read config file failed"); + return false; + } + Json::CharReaderBuilder builder; + std::unique_ptr reader(builder.newCharReader()); + std::string errorMsg; + if (!reader->parse(&*jsonString.begin(), &*jsonString.end(), &jsonObjRoot, &errorMsg)) { + PGCGS_LOGE("ParseConfigFileToJsonObj: parse json failed, errorMsg:%{public}s", errorMsg.c_str()); + return false; + } + return true; +} + +} // namespace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS \ No newline at end of file diff --git a/cgroup_sched/framework/process_group/src/cgroup_controller.cpp b/cgroup_sched/framework/process_group/src/cgroup_controller.cpp new file mode 100644 index 00000000..9fcef4d3 --- /dev/null +++ b/cgroup_sched/framework/process_group/src/cgroup_controller.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include +#include +#include "cgroup_controller.h" +#include "process_group_log.h" +#include "process_group_util.h" + + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +CgroupController::CgroupController(const std::string& name, const std::string& path) + : name_(name), path_(path), policyToTaskFd_(SP_CNT, -1), policyToProcFd_(SP_CNT, -1) {} + +CgroupController::~CgroupController() +{ + for (auto& fd : policyToTaskFd_) { + if (fd != -1) { + close(fd); + fd = -1; + } + } + for(auto& fd : policyToProcFd_) { + if (fd != -1) { + close(fd); + fd = -1; + } + } +} + +CgroupController::CgroupController(CgroupController&& controller) + : name_(std::move(controller.name_)), path_(std::move(controller.path_)), + policyToTaskFd_(std::move(controller.policyToTaskFd_)), policyToProcFd_(std::move(controller.policyToProcFd_)) {} + +CgroupController& CgroupController::operator=(CgroupController&& controller) +{ + name_ = std::move(controller.name_); + path_ = std::move(controller.path_), + policyToTaskFd_ = std::move(controller.policyToTaskFd_); + policyToProcFd_ = std::move(controller.policyToProcFd_); + return *this; +} + +bool CgroupController::IsEnabled() +{ + std::string filePath(path_ + "/tasks"); + static bool enabled = !access(filePath.c_str(), F_OK); + return enabled; +} + +bool CgroupController::SetThreadSchedPolicy(int tid, SchedPolicy policy, bool isSetThreadGroup) +{ + int fd = (isSetThreadGroup ? policyToProcFd_[policy] : policyToTaskFd_[policy]); + if (fd < 0) { + PGCGS_LOGI("SetThreadSchedPolicy failed; fd = %{public}d", fd); + errno = EINVAL; + return false; + } + if (!AddTidToCgroup(tid, fd)) { + return false; + } + return true; +} + +bool CgroupController::AddTidToCgroup(int tid, int fd) +{ + std::string value = std::to_string(tid); + if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) == value.length()) { + return true; + } + /* If the thread is in the process of exiting, don't flag an error. */ + if (errno == ESRCH) { + return true; + } + PGCGS_LOGE("AddTidToCgroup failed to write; fd = %{public}d, errno = %{public}d", fd, errno); + return false; +} + +bool CgroupController::AddSchedPolicy(SchedPolicy policy, const std::string& subgroup) +{ + return AddThreadSchedPolicy(policy, subgroup) && AddThreadGroupSchedPolicy(policy, subgroup); +} + +bool CgroupController::GetTaskGroup(int tid, std::string& subgroup) +{ + std::string content; + std::string filePath = StringPrintf("/proc/%d/cgroup", tid); + if (!ReadFileToStringForVFS(filePath, content)) { + PGCGS_LOGE("GetTaskGroup: fail to read = %{public}s", filePath.c_str()); + return -1; + } + std::string cgTag = StringPrintf(":%s:", name_.c_str()); + size_t startPos = content.find(cgTag); + if (startPos == std::string::npos) { + return false; + } + startPos += cgTag.length() + 1; + size_t endPos = content.find('\n', startPos); + if (endPos == std::string::npos) { + subgroup = content.substr(startPos, std::string::npos); + } else { + subgroup = content.substr(startPos, endPos - startPos); + } + return true; +} + +bool CgroupController::AddThreadSchedPolicy(SchedPolicy policy, const std::string& subgroup) +{ + std::string filePath; + if (subgroup.empty()) { + filePath = StringPrintf("%s/tasks", path_.c_str()); + } else { + filePath = StringPrintf("%s/%s/tasks", path_.c_str(), subgroup.c_str()); + } + int fd = TEMP_FAILURE_RETRY(open(filePath.c_str(), O_WRONLY | O_CLOEXEC)); + if (fd < 0) { + PGCGS_LOGE("AddThreadSchedPolicy open file failed; file = %{public}s, fd = %{public}d ", filePath.c_str(), fd); + return false; + } + policyToTaskFd_[policy] = fd; + return true; +} + +bool CgroupController::AddThreadGroupSchedPolicy(SchedPolicy policy, const std::string& subgroup) { + std::string filePath; + if (subgroup.empty()) { + filePath = StringPrintf("%s/cgroup.procs", path_.c_str()); + } else { + filePath = StringPrintf("%s/%s/cgroup.procs", path_.c_str(), subgroup.c_str()); + } + int fd = TEMP_FAILURE_RETRY(open(filePath.c_str(), O_WRONLY | O_CLOEXEC)); + if (fd < 0) { + PGCGS_LOGE("AddThreadGroupSchedPolicy open file failed; file = %{public}s'; fd = %{public}d ", filePath.c_str(), fd); + return false; + } + policyToProcFd_[policy] = fd; + return true; +} + +} // namespace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS \ No newline at end of file diff --git a/cgroup_sched/framework/process_group/src/cgroup_map.cpp b/cgroup_sched/framework/process_group/src/cgroup_map.cpp new file mode 100644 index 00000000..cade2f1a --- /dev/null +++ b/cgroup_sched/framework/process_group/src/cgroup_map.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2021 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 "cgroup_map.h" +#include "process_group_log.h" + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +namespace { + constexpr const char* const JSON_KEY_CGROUPS = "Cgroups"; + constexpr const char* const JSON_KEY_CONTROLLER = "controller"; + constexpr const char* const JSON_KEY_PATH = "path"; + constexpr const char* const JSON_KEY_SCHED_POLICY = "sched_policy"; +} + + +CgroupMap& CgroupMap::GetInstance() +{ + static CgroupMap instance; + return instance; +} + +bool CgroupMap::SetThreadSchedPolicy(int tid, SchedPolicy policy, bool isThreadGroup) +{ + for(auto it = controllers_.begin(); it != controllers_.end(); ++it) { + CgroupController& controller = it -> second; + if (controller.IsEnabled()) { + if (!controller.SetThreadSchedPolicy(tid, policy, isThreadGroup)) { + PGCGS_LOGD("SetThreadSchedPolicy failed, controller = %{public}s, policy = %{public}d.", + controller.GetName().c_str(), policy); + } + } + } + return true; +} + +void CgroupMap::AddCgroupController(const std::string& name, CgroupController& controller) +{ + controllers_.insert(std::make_pair(name, std::move(controller))); +} + +bool CgroupMap::loadConfigFromJsonObj(const Json::Value& jsonObj) +{ + const Json::Value& jsonArrObj = jsonObj[JSON_KEY_CGROUPS]; + // check json format + if (jsonArrObj.isNull() || !jsonArrObj.isArray()) { + PGCGS_LOGI("Cgroups json config format error, disabled cgroup-setting."); + return false; + } + int count = 0; + for (Json::Value::ArrayIndex i = 0; i < jsonArrObj.size(); ++i) { + const Json::Value& cgroupObj = jsonArrObj[i]; + // check cgroup schedule policy json config format + if (!CheckCgroupJsonConfig(cgroupObj)) { + PGCGS_LOGE("cgroup json config format error, ingore it."); + continue; + } + + std::string name = cgroupObj[JSON_KEY_CONTROLLER].asString(); + std::string rootPath = cgroupObj[JSON_KEY_PATH].asString(); + const Json::Value& schedPolicyJsonObj = cgroupObj[JSON_KEY_SCHED_POLICY]; + CgroupController controller(name, rootPath); + + for (int i = 0; i < SP_CNT; i++) { + SchedPolicy policy = SchedPolicy(i); + const char * keyString = GetSchedPolicyFullName(policy); + std::string relPath = schedPolicyJsonObj[keyString].asString(); + controller.AddSchedPolicy(policy, relPath); + } + this->AddCgroupController(name, controller); + count++; + } + if (count == 0) { + return false; + } + PGCGS_LOGI("loadConfigFile ok, CgroupMap is enabled!"); + return true; +} + +bool CgroupMap::CheckCgroupJsonConfig(const Json::Value& cgroupObj) +{ + if (cgroupObj[JSON_KEY_CONTROLLER].isNull() || !cgroupObj[JSON_KEY_CONTROLLER].isString() + || cgroupObj[JSON_KEY_PATH].isNull() || !cgroupObj[JSON_KEY_PATH].isString() + || cgroupObj[JSON_KEY_SCHED_POLICY].isNull() || !cgroupObj[JSON_KEY_SCHED_POLICY].isObject()) { + PGCGS_LOGE("controller json config format error; content = %{public}s", cgroupObj.asString().c_str()); + return false; + } + for (int i = SP_DEFAULT; i < SP_CNT; i++) { + SchedPolicy policy = SchedPolicy(i); + const char* string = GetSchedPolicyFullName(policy); + if (!strcmp(string, "error")) { + return false; + } + const Json::Value& jsonObj = cgroupObj[JSON_KEY_SCHED_POLICY][string]; + if (jsonObj.isNull() || !jsonObj.isString()) { + return false; + } + } + return true; +} + +bool CgroupMap::findFristEnableCgroupController(CgroupController** p) +{ + for (auto it = controllers_.begin(); it != controllers_.end(); ++it){ + if (it->second.IsEnabled()) { + *p = &(it->second); + return true; + } + } + return false; +} + +} // namespace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS \ No newline at end of file diff --git a/cgroup_sched/framework/process_group/src/process_group_util.cpp b/cgroup_sched/framework/process_group/src/process_group_util.cpp new file mode 100644 index 00000000..ca773620 --- /dev/null +++ b/cgroup_sched/framework/process_group/src/process_group_util.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include +#include "process_group_log.h" +#include "process_group_util.h" + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +std::string FormatString(const char* fmt, va_list vararg) +{ + static std::vector buffer(512); + // Attempt to just print to the current buffer + int len = vsnprintf(&buffer[0], buffer.size(), fmt, vararg); + if (len < 0 || static_cast(len) >= buffer.size()) { + // Buffer was not large enough, calculate the required size and resize the buffer + len = vsnprintf(NULL, 0, fmt, vararg); + buffer.resize(len + 1); + // Print again + vsnprintf(&buffer[0], buffer.size(), fmt, vararg); + } + return std::string(buffer.data(), len); +} + +std::string StringPrintf(const char* fmt, ...) +{ + va_list vararg; + va_start(vararg, fmt); + std::string result = FormatString(fmt, vararg); + va_end(vararg); + return result; +} + +bool ReadFileToString(const std::string& fileName, std::string& content) +{ + int fd = open(fileName.c_str(), O_RDONLY | O_CLOEXEC); + if (fd < 0) { + return false; + } + struct stat sb {}; + if (fstat(fd, &sb) != -1 && sb.st_size > 0) { + content.resize(sb.st_size); + } + ssize_t n; + size_t remaining = sb.st_size; + char* p = const_cast(content.data()); + while (remaining > 0) { + n = read(fd, p, remaining); + if (n < 0) { + return false; + } + p += n; + remaining -= n; + } + close(fd); + return true; +} + + +bool ReadFileToStringForVFS(const std::string& fileName, std::string& content) { + std::ifstream fin(fileName.c_str(), std::ios::in); + if (!fin) { + return false; + } + fin >> content; + return true; +} + + +bool WriteStringToFile(int fd, const std::string& content) +{ + const char *p = content.data(); + size_t remaining = content.size(); + while (remaining > 0) { + ssize_t n = write(fd, p, remaining); + if(n == -1) { + return false; + } + p += n; + remaining -= n; + } + return true; +} + +bool WriteStringToFile(const std::string& content, const std::string& filePath) +{ + if (access(filePath.c_str(), W_OK)) { + return false; + } + int fd = open(filePath.c_str(), O_WRONLY | O_CLOEXEC); + if (fd < 0) { + PGCGS_LOGE("WriteStringToFile fail. file: %{public}s, fd = %{public}d", filePath.c_str(), fd); + return false; + } + bool result = WriteStringToFile(fd, content); + close(fd); + return result; +} + +} // namespace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS \ No newline at end of file diff --git a/cgroup_sched/framework/process_group/src/sched_policy.cpp b/cgroup_sched/framework/process_group/src/sched_policy.cpp new file mode 100644 index 00000000..1fd74555 --- /dev/null +++ b/cgroup_sched/framework/process_group/src/sched_policy.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 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 +#include +#include +#include "process_group_util.h" +#include "sched_policy.h" +#include "cgroup_map.h" +#include "cgroup_action.h" + +namespace OHOS { +namespace ResourceSchedule { +namespace CgroupSetting { + +int SetThreadSchedPolicy(int tid, int policy) +{ + if (policy < SP_DEFAULT || policy > SP_MAX || tid < 0) { + return -1; + } + if (tid == 0) { + tid = gettid(); + } + SchedPolicy schedPolicy = SchedPolicy(policy); + return CgroupAction::GetInstance().SetThreadSchedPolicy(tid, schedPolicy) ? 0 : -1; +} + +int SetThreadGroupSchedPolicy(int pid, int policy) { + if (policy < SP_DEFAULT || policy > SP_MAX || pid < 0) { + return -1; + } + if (pid == 0) { + pid = getpid(); + } + SchedPolicy schedPolicy = SchedPolicy(policy); + return CgroupAction::GetInstance().SetThreadGroupSchedPolicy(pid, schedPolicy) ? 0 : -1; +} + +int GetThreadSchedPolicy(int tid, SchedPolicy* policy) { + if( tid < 0) { + return -1; + } + if (tid == 0) { + tid = gettid(); + } + return CgroupAction::GetInstance().GetSchedPolicy(tid, policy); +} + +const char* GetSchedPolicyShortenedName(SchedPolicy policy) +{ + static constexpr const char* kShortenedNames[] = { + [SP_DEFAULT] = "df", + [SP_BACKGROUND] = "bg", + [SP_FOREGROUND] = "fg", + [SP_SYSTEM] = "sy", + [SP_TOP_APP] = "ta", + }; + constexpr int size = sizeof(kShortenedNames) / sizeof(const char*); + static_assert(size == SP_CNT, "miss name"); + if (policy >= SP_DEFAULT && policy < SP_CNT && kShortenedNames[policy] != NULL) { + return kShortenedNames[policy]; + } else { + return "error"; + } +} + +const char* GetSchedPolicyFullName(SchedPolicy policy) +{ + static constexpr const char* kFullNames[] = { + [SP_DEFAULT] = "sp_default", + [SP_BACKGROUND] = "sp_background", + [SP_FOREGROUND] = "sp_foreground", + [SP_SYSTEM] = "sp_system", + [SP_TOP_APP] = "sp_top_app", + }; + constexpr int size = sizeof(kFullNames) / sizeof(const char*); + static_assert(size == SP_CNT, "miss name"); + if (policy >= SP_DEFAULT && policy < SP_CNT && kFullNames[policy] != NULL) { + return kFullNames[policy]; + } else { + return "error"; + } +} + +} // namepsace CgroupSetting +} // namespace ResourceSchedule +} // namespace OHOS diff --git a/cgroup_sched/framework/sched_controller/app_state_observer.cpp b/cgroup_sched/framework/sched_controller/app_state_observer.cpp new file mode 100644 index 00000000..94f1bc0d --- /dev/null +++ b/cgroup_sched/framework/sched_controller/app_state_observer.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2021 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 "app_state_observer.h" + +#include "sched_controller.h" +#include "cgroup_event_handler.h" +#include "cgroup_sched_log.h" +#include "ressched_utils.h" +#include "res_type.h" +#include "supervisor.h" + +namespace OHOS { +namespace ResourceSchedule { + +namespace { + constexpr HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_RMS, "RmsAppStateObserver"}; +} + +void RmsApplicationStateObserver::OnForegroundApplicationChanged(const AppStateData &appStateData) +{ + if (!ValidateAppStateData(appStateData)) { + CGS_LOGE("%{public}s : validate app state data failed!", __func__); + return; + } + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, appStateData] { + cgHander->HandleForegroundApplicationChanged(appStateData.uid, appStateData.bundleName, appStateData.state); + }); + } + + std::string payload = std::to_string(appStateData.uid) + "," + // uid + appStateData.bundleName; // bundle name + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_APP_STATE_CHANGE, appStateData.state, payload); +} + +void RmsApplicationStateObserver::OnAbilityStateChanged(const AbilityStateData &abilityStateData) +{ + if (!ValidateAbilityStateData(abilityStateData)) { + CGS_LOGE("%{public}s : validate ability state data failed!", __func__); + return; + } + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, abilityStateData] { + cgHander->HandleAbilityStateChanged(abilityStateData.uid, abilityStateData.pid, abilityStateData.bundleName, + abilityStateData.abilityName, abilityStateData.token, abilityStateData.abilityState); + }); + } + + std::string payload = std::to_string(abilityStateData.pid) + "," + // pid + std::to_string(abilityStateData.uid) + "," + // uid + abilityStateData.bundleName; // bundle name + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_ABILITY_STATE_CHANGE, abilityStateData.abilityState, payload); +} + +void RmsApplicationStateObserver::OnExtensionStateChanged(const AbilityStateData &abilityStateData) +{ + if (!ValidateAbilityStateData(abilityStateData)) { + CGS_LOGE("%{public}s : validate extension state data failed!", __func__); + return; + } + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, abilityStateData] { + cgHander->HandleExtensionStateChanged(abilityStateData.uid, abilityStateData.pid, abilityStateData.bundleName, + abilityStateData.abilityName, abilityStateData.token, abilityStateData.abilityState); + }); + } + + std::string payload = std::to_string(abilityStateData.pid) + "," + // pid + std::to_string(abilityStateData.uid) + "," + // uid + abilityStateData.bundleName; // bundle name + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_EXTENSION_STATE_CHANGE, abilityStateData.abilityState, payload); +} + +void RmsApplicationStateObserver::OnProcessCreated(const ProcessData &processData) +{ + if (!ValidateProcessData(processData)) { + CGS_LOGE("%{public}s : validate process data failed!", __func__); + return; + } + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, processData] { + cgHander->HandleProcessCreated(processData.uid, processData.pid, processData.bundleName); + }); + } + + std::string payload = std::to_string(processData.pid) + "," + // pid + std::to_string(processData.uid) + "," + // uid + processData.bundleName; // bundle name + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_PROCESS_STATE_CHANGE, 0, payload); +} + +void RmsApplicationStateObserver::OnProcessDied(const ProcessData &processData) +{ + if (!ValidateProcessData(processData)) { + CGS_LOGE("%{public}s : validate process data failed!", __func__); + return; + } + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, processData] { + cgHander->HandleProcessDied(processData.uid, processData.pid, processData.bundleName); + }); + } + + std::string payload = std::to_string(processData.pid) + "," + // pid + std::to_string(processData.uid) + "," + // uid + processData.bundleName; // bundle name + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_PROCESS_STATE_CHANGE, 1, payload); +} + +} // namespace ResourceSchedule +} // namespace OHOS diff --git a/cgroup_sched/framework/sched_controller/cgroup_adjuster.cpp b/cgroup_sched/framework/sched_controller/cgroup_adjuster.cpp new file mode 100644 index 00000000..2f598e9a --- /dev/null +++ b/cgroup_sched/framework/sched_controller/cgroup_adjuster.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2021 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 "cgroup_adjuster.h" + +#include + +#include "app_mgr_constants.h" +#include "cgroup_event_handler.h" +#include "cgroup_sched_common.h" +#include "cgroup_sched_log.h" +#include "sched_controller.h" +#include "sched_policy.h" +#include "ressched_utils.h" +#include "res_type.h" +#include "wm_common.h" +#include + +namespace OHOS { +namespace ResourceSchedule { + +using OHOS::AppExecFwk::ApplicationState; +using OHOS::AppExecFwk::AbilityState; +using OHOS::AppExecFwk::ExtensionState; +using OHOS::Rosen::WindowType; + +namespace { + constexpr HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_RMS, "CgroupAdjuster"}; +} + +void CgroupAdjuster::InitAdjuster() +{ + auto handler = SchedController::GetInstance().GetCgroupEventHandler(); + if (handler != nullptr) { + handler->PostTask([this] { + this->AdjustSelfProcessGroup(); + }); + } +} + +void CgroupAdjuster::AdjustProcessGroup(Application &app, ProcessRecord &pr, AdjustSource source) +{ + CGS_LOGI("%{public}s for %{public}d, source : %{public}d", __func__, pr.GetPid(), source); + ComputeProcessGroup(app, pr, source); + ApplyProcessGroup(pr); +} + +void CgroupAdjuster::AdjustAllProcessGroup(Application &app, AdjustSource source) +{ + auto pidsMap = app.GetPidsMap(); + for (auto iter = pidsMap.begin(); iter != pidsMap.end(); iter++) + { + auto pr = iter->second; + AdjustProcessGroup(app, *(pr.get()), source); + } +} + +inline void CgroupAdjuster::AdjustSelfProcessGroup() +{ + int pid = getpid(); + int group = (int)(CgroupSetting::SchedPolicy::SP_FOREGROUND); + int ret = CgroupSetting::SetThreadGroupSchedPolicy(pid, group); + if (ret != 0) { + CGS_LOGE("%{public}s set %{public}d to group %{public}d failed, ret=%{public}d!", __func__, pid, group, ret); + } +} + +void CgroupAdjuster::ComputeProcessGroup(Application &app, ProcessRecord &pr, AdjustSource source) +{ + int32_t appState = app.state_; + int32_t abilityState = pr.abilityState_; + SchedPolicy group = SchedPolicy::SP_DEFAULT; + auto focusProcess = app.focusedProcess_; + + { + ChronoScope cs("ComputeProcessGroup"); + + if (source == AdjustSource::ADJS_FG_APP_CHANGE && appState == VALUE_INT(ApplicationState::APP_STATE_BACKGROUND)) { + group = SchedPolicy::SP_BACKGROUND; // like unfocused + } else if (source == AdjustSource::ADJS_FG_APP_CHANGE && appState == VALUE_INT(ApplicationState::APP_STATE_FOREGROUND)) { + group = SchedPolicy::SP_TOP_APP; + } else if (focusProcess != nullptr || pr.focused_ || + abilityState == VALUE_INT(AbilityState::ABILITY_STATE_FOREGROUND) || + appState == VALUE_INT(ApplicationState::APP_STATE_FOREGROUND)) { + group = SchedPolicy::SP_TOP_APP; // focused process --> top-app + if (pr.windowType_ == VALUE_INT(WindowType::WINDOW_TYPE_FLOAT)) { + group = SchedPolicy::SP_FOREGROUND; // float window process --> fg + } + } else if (abilityState == VALUE_INT(AbilityState::ABILITY_STATE_BACKGROUND)) { + group = SchedPolicy::SP_BACKGROUND; // background process -> bg + } + + if (group == SchedPolicy::SP_BACKGROUND && pr.runningContinuousTask_) { + group = SchedPolicy::SP_FOREGROUND; // move background key task to fg + } + + pr.setSchedGroup_ = group; + } // end ChronoScope +} + +void CgroupAdjuster::ApplyProcessGroup(ProcessRecord &pr) +{ + ChronoScope cs("ApplyProcessGroup"); + if (pr.curSchedGroup_ != pr.setSchedGroup_) { + pid_t pid = pr.GetPid(); + int ret = CgroupSetting::SetThreadGroupSchedPolicy(pid, (int)pr.setSchedGroup_); + if (ret != 0) { + CGS_LOGE("%{public}s set %{public}d to group %{public}d failed, ret=%{public}d!", __func__, pid, pr.setSchedGroup_, ret); + return; + } + + pr.lastSchedGroup_ = pr.curSchedGroup_; + pr.curSchedGroup_ = pr.setSchedGroup_; + CGS_LOGI("%{public}s Set %{public}d's cgroup from %{public}d to %{public}d.", + __func__, pr.GetPid(), pr.lastSchedGroup_, pr.curSchedGroup_); + + std::string payload = std::to_string(pr.GetPid()) + "," + + std::to_string(pr.GetUid()) + "," + + pr.GetName() + "," + + std::to_string(VALUE_INT(pr.lastSchedGroup_)) + "," + + std::to_string(VALUE_INT(pr.curSchedGroup_)); + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_CGROUP_ADJUSTER, 0, payload); + } +} + +} // namespace ResourceSchedule +} // namespace OHOS \ No newline at end of file diff --git a/cgroup_sched/framework/sched_controller/cgroup_event_handler.cpp b/cgroup_sched/framework/sched_controller/cgroup_event_handler.cpp new file mode 100644 index 00000000..ad4190e2 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/cgroup_event_handler.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2021 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 "cgroup_event_handler.h" + +#include "sched_controller.h" +#include "cgroup_adjuster.h" +#include "cgroup_sched_common.h" +#include "cgroup_sched_log.h" +#include "ressched_utils.h" +#include "res_type.h" + +namespace OHOS { +namespace ResourceSchedule { + +namespace { + constexpr HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_RMS, "CgroupEventHandler"}; +} + +CgroupEventHandler::CgroupEventHandler(const std::shared_ptr &runner) + : EventHandler(runner) +{} + +CgroupEventHandler::~CgroupEventHandler() +{ + supervisor_ = nullptr; +} + +void CgroupEventHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer& event) +{ + switch (event->GetInnerEventId()) { + case INNER_EVENT_ID_REG_WINDOW_FOCUS_STATE: { + ChronoScope cs("Delayed SubscribeWindowState."); + SchedController::GetInstance().SubscribeWindowState(); + break; + } + default: + break; + } +} + +void CgroupEventHandler::SetSupervisor(std::shared_ptr supervisor) +{ + supervisor_ = supervisor; +} + +void CgroupEventHandler::HandleForegroundApplicationChanged(uid_t uid, std::string bundleName, int32_t state) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}s, %{public}d", __func__, uid, bundleName.c_str(), state); + ChronoScope cs("HandleForegroundApplicationChanged"); + std::shared_ptr app = supervisor_->GetAppRecordNonNull(uid, bundleName); + app->state_ = state; + SchedController::GetInstance().AdjustAllProcessGroup(*(app.get()), AdjustSource::ADJS_FG_APP_CHANGE); +} + +void CgroupEventHandler::HandleAbilityStateChanged(uid_t uid, pid_t pid, std::string bundleName, + std::string abilityName, sptr token, int32_t abilityState) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}d, %{public}s, %{public}s, %{public}p, %{public}d", + __func__, uid, pid, bundleName.c_str(), abilityName.c_str(), token.GetRefPtr(), abilityState); + ChronoScope cs("HandleAbilityStateChanged"); + auto app = supervisor_->GetAppRecordNonNull(uid, bundleName); + auto procRecord = app->GetProcessRecordNonNull(pid, abilityName); + procRecord->abilityState_ = abilityState; + procRecord->token_ = token; + SchedController::GetInstance().AdjustProcessGroup(*(app.get()), *(procRecord.get()), AdjustSource::ADJS_ABILITY_STATE); +} + +void CgroupEventHandler::HandleExtensionStateChanged(uid_t uid, pid_t pid, std::string bundleName, + std::string abilityName, sptr token, int32_t extensionState) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}d, %{public}s, %{public}s, %{public}p, %{public}d", + __func__, uid, pid, bundleName.c_str(), abilityName.c_str(), token.GetRefPtr(), extensionState); + ChronoScope cs("HandleExtensionStateChanged"); + auto app = supervisor_->GetAppRecordNonNull(uid, bundleName); + auto procRecord = app->GetProcessRecordNonNull(pid, abilityName); + procRecord->extensionState_ = extensionState; + procRecord->token_ = token; + SchedController::GetInstance().AdjustProcessGroup(*(app.get()), *(procRecord.get()), AdjustSource::ADJS_EXTENSION_STATE); +} + +void CgroupEventHandler::HandleProcessCreated(uid_t uid, pid_t pid, std::string bundleName) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}d, %{public}s", __func__, uid, pid, bundleName.c_str()); + ChronoScope cs("HandleProcessCreated"); + std::shared_ptr app = supervisor_->GetAppRecordNonNull(uid, bundleName); + std::shared_ptr procRecord = std::make_shared(uid, pid, bundleName); + app->AddProcessRecord(procRecord); + SchedController::GetInstance().AdjustProcessGroup(*(app.get()), *(procRecord.get()), AdjustSource::ADJS_PROCESS_CREATE); +} + +void CgroupEventHandler::HandleProcessDied(uid_t uid, pid_t pid, std::string bundleName) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}d, %{public}s", __func__, uid, pid, bundleName.c_str()); + std::shared_ptr app = supervisor_->GetAppRecord(uid); + if (app == nullptr) { + CGS_LOGE("%{public}s : application %{public}s not exist!", __func__, bundleName.c_str()); + return; + } + std::shared_ptr processRecord = app->RemoveProcessRecord(pid); +} + +void CgroupEventHandler::HandleTransientTaskStart(uid_t uid, pid_t pid, std::string packageName) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}d, %{public}s", __func__, uid, pid, packageName.c_str()); + auto app = supervisor_->GetAppRecordNonNull(uid, packageName); + auto procRecord = app->GetProcessRecord(pid); + if (procRecord == nullptr) { + return; + } + procRecord->runningTransientTask_ = true; +} + +void CgroupEventHandler::HandleTransientTaskEnd(uid_t uid, pid_t pid, std::string packageName) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}d, %{public}s", __func__, uid, pid, packageName.c_str()); + auto app = supervisor_->GetAppRecordNonNull(uid, packageName); + auto procRecord = app->GetProcessRecord(pid); + if (procRecord == nullptr) { + return; + } + procRecord->runningTransientTask_ = false; +} + +void CgroupEventHandler::HandleContinuousTaskStart(uid_t uid, pid_t pid, std::string abilityName) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}d, %{public}s", __func__, uid, pid, abilityName.c_str()); + ChronoScope cs("HandleContinuousTaskStart"); + auto app = supervisor_->GetAppRecordNonNull(uid, abilityName); + auto procRecord = app->GetProcessRecord(pid); + if (procRecord == nullptr) { + return; + } + procRecord->runningContinuousTask_ = true; + SchedController::GetInstance().AdjustProcessGroup(*(app.get()), *(procRecord.get()), AdjustSource::ADJS_CONTINUOUS_BEGIN); +} + +void CgroupEventHandler::HandleContinuousTaskCancel(uid_t uid, pid_t pid, std::string abilityName) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}d, %{public}s", __func__, uid, pid, abilityName.c_str()); + ChronoScope cs("HandleContinuousTaskCancel"); + auto app = supervisor_->GetAppRecordNonNull(uid, abilityName); + auto procRecord = app->GetProcessRecord(pid); + if (procRecord == nullptr) { + return; + } + procRecord->runningContinuousTask_ = false; + SchedController::GetInstance().AdjustProcessGroup(*(app.get()), *(procRecord.get()), AdjustSource::ADJS_CONTINUOUS_END); +} + +void CgroupEventHandler::HandleFocusedWindow(uint32_t windowId, sptr abilityToken, WindowType windowType, int32_t displayId) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}p, %{public}d, %{public}d", __func__, windowId, abilityToken.GetRefPtr(), windowType, displayId); + std::shared_ptr app = nullptr; + std::shared_ptr procRecord = nullptr; + { + ChronoScope cs("HandleFocusedWindow"); + supervisor_->SearchAbilityToken(app, procRecord, abilityToken); + if (app == nullptr || procRecord == nullptr) { + return; + } + auto pidsMap = app->GetPidsMap(); + for (auto iter = pidsMap.begin(); iter != pidsMap.end(); iter++) + { + auto pr = iter->second; + if (pr != procRecord) { + pr->focused_ = false; + } + } + procRecord->focused_ = true; + procRecord->windowType_ = VALUE_INT(windowType); + app->focusedProcess_ = procRecord; + SchedController::GetInstance().AdjustAllProcessGroup(*(app.get()), AdjustSource::ADJS_FOCUSED_WINDOW); + } + + std::string payload = std::to_string(procRecord->GetPid()) + "," + // pid + std::to_string(procRecord->GetUid()) + "," + // uid + app->GetName() + "," + // bundle name + std::to_string(windowId) + "," + // window id + std::to_string(VALUE_INT(windowType)) + "," + // window type + std::to_string(displayId);// display id + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_WINDOW_FOCUS, 0, payload); +} + +void CgroupEventHandler::HandleUnfocusedWindow(uint32_t windowId, sptr abilityToken, WindowType windowType, int32_t displayId) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("%{public}s : supervisor nullptr!", __func__); + return; + } + CGS_LOGD("%{public}s : %{public}d, %{public}p, %{public}d, %{public}d", __func__, windowId, abilityToken.GetRefPtr(), windowType, displayId); + std::shared_ptr app = nullptr; + std::shared_ptr procRecord = nullptr; + { + ChronoScope cs("HandleUnfocusedWindow"); + supervisor_->SearchAbilityToken(app, procRecord, abilityToken); + if (app == nullptr || procRecord == nullptr) { + return; + } + procRecord->focused_ = false; + procRecord->windowType_ = VALUE_INT(windowType); + if (app->focusedProcess_ == procRecord) { + app->focusedProcess_ = nullptr; + } + SchedController::GetInstance().AdjustAllProcessGroup(*(app.get()), AdjustSource::ADJS_UNFOCUSED_WINDOW); + } + + std::string payload = std::to_string(procRecord->GetPid()) + "," + // pid + std::to_string(procRecord->GetUid()) + "," + // uid + app->GetName() + "," + // bundle name + std::to_string(windowId) + "," + // window id + std::to_string(VALUE_INT(windowType)) + "," + // window type + std::to_string(displayId);// display id + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_WINDOW_FOCUS, 1, payload); +} + +} // namespace ResourceSchedule +} // namespace OHOS diff --git a/cgroup_sched/framework/sched_controller/continuous_task_observer.cpp b/cgroup_sched/framework/sched_controller/continuous_task_observer.cpp new file mode 100644 index 00000000..ab8e0d51 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/continuous_task_observer.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021 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 "continuous_task_observer.h" + +#include "cgroup_sched_log.h" +#include "sched_controller.h" +#include "cgroup_event_handler.h" +#include "ressched_utils.h" +#include "res_type.h" + +namespace OHOS { +namespace ResourceSchedule { + +namespace { + constexpr HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_RMS, "ContinuousTaskObserver"}; +} + +void ContinuousTaskObserver::OnSubscribeResult(ContinuousTaskConstant::SubscribeResult result) +{ + CGS_LOGI("%{public}s result:%{public}d!", __func__, result); +} + +void ContinuousTaskObserver::OnUnsubscribeResult(ContinuousTaskConstant::SubscribeResult result) +{ + CGS_LOGI("%{public}s result:%{public}d!", __func__, result); +} + +void ContinuousTaskObserver::OnContinuousTaskStart(const std::shared_ptr &eventData) +{ + if (!ValidateTransientTaskAppInfo(eventData)) { + CGS_LOGE("%{public}s failed, invalid event data!", __func__); + return; + } + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, eventData] { + cgHander->HandleContinuousTaskStart(eventData->GetCreatorUid(), eventData->GetCreatorPid(), eventData->GetAbilityName()); + }); + } + + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_CONTINUOUS_TASK, 0, PackPayload(eventData)); +} + +void ContinuousTaskObserver::OnContinuousTaskCancel(const std::shared_ptr &eventData) +{ + if (!ValidateTransientTaskAppInfo(eventData)) { + CGS_LOGE("%{public}s failed, invalid event data!", __func__); + return; + } + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, eventData] { + cgHander->HandleContinuousTaskCancel(eventData->GetCreatorUid(), eventData->GetCreatorPid(), eventData->GetAbilityName()); + }); + } + + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_CONTINUOUS_TASK, 0, PackPayload(eventData)); +} + +void ContinuousTaskObserver::OnDied() +{ +} + +} // namespace ResourceSchedule +} // namespace OHOS diff --git a/cgroup_sched/framework/sched_controller/include/app_state_observer.h b/cgroup_sched/framework/sched_controller/include/app_state_observer.h new file mode 100644 index 00000000..febf7e4f --- /dev/null +++ b/cgroup_sched/framework/sched_controller/include/app_state_observer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 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 APP_STATE_OBSERVER_H +#define APP_STATE_OBSERVER_H + +#include "application_state_observer_stub.h" + +namespace OHOS { +namespace ResourceSchedule { +using OHOS::AppExecFwk::ApplicationStateObserverStub; +using OHOS::AppExecFwk::AppStateData; +using OHOS::AppExecFwk::AbilityStateData; +using OHOS::AppExecFwk::ProcessData; + +class RmsApplicationStateObserver : public ApplicationStateObserverStub { +public: + void OnForegroundApplicationChanged(const AppStateData &appStateData) override; + void OnAbilityStateChanged(const AbilityStateData &abilityStateData) override; + void OnExtensionStateChanged(const AbilityStateData &abilityStateData) override; + void OnProcessCreated(const ProcessData &processData) override; + void OnProcessDied(const ProcessData &processData) override; + +private: + inline bool ValidateAppStateData(const AppStateData &appStateData) const + { + return appStateData.uid > 0 + && appStateData.bundleName.size() > 0; + } + + inline bool ValidateAbilityStateData(const AbilityStateData &abilityStateData) const + { + return abilityStateData.uid > 0 && abilityStateData.pid >= 0 + && abilityStateData.bundleName.size() > 0 + && abilityStateData.abilityName.size() > 0 + && abilityStateData.token != nullptr; + } + + inline bool ValidateProcessData(const ProcessData &processData) const + { + return processData.uid > 0 && processData.pid >= 0 + && processData.bundleName.size() > 0; + } + +}; + +} // namespace ResourceSchedule +} // namespace OHOS +#endif // APP_STATE_OBSERVER_H diff --git a/cgroup_sched/framework/sched_controller/include/cgroup_adjuster.h b/cgroup_sched/framework/sched_controller/include/cgroup_adjuster.h new file mode 100644 index 00000000..def135f0 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/include/cgroup_adjuster.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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 CGROUP_ADJUSTER_H +#define CGROUP_ADJUSTER_H + +#include + +#include "supervisor.h" + +namespace OHOS { +namespace ResourceSchedule { + +enum class AdjustSource { + ADJS_BEGIN = 0, + ADJS_FG_APP_CHANGE = ADJS_BEGIN, + ADJS_ABILITY_STATE, + ADJS_EXTENSION_STATE, + ADJS_PROCESS_CREATE, + ADJS_TRANSIENT_BEGIN, + ADJS_TRANSIENT_END, + ADJS_CONTINUOUS_BEGIN, + ADJS_CONTINUOUS_END, + ADJS_FOCUSED_WINDOW, + ADJS_UNFOCUSED_WINDOW, + ADJS_END +}; + +class CgroupAdjuster { +public: + CgroupAdjuster() = default; + ~CgroupAdjuster() = default; + void InitAdjuster(); + void AdjustProcessGroup(Application &app, ProcessRecord &pr, AdjustSource source); + void AdjustAllProcessGroup(Application &app, AdjustSource source); + +private: + void ComputeProcessGroup(Application &app, ProcessRecord &pr, AdjustSource source); + void ApplyProcessGroup(ProcessRecord &pr); + inline void AdjustSelfProcessGroup(); +}; +} // namespace ResourceSchedule +} // namespace OHOS +#endif // CGROUP_ADJUSTER_H \ No newline at end of file diff --git a/cgroup_sched/framework/sched_controller/include/cgroup_event_handler.h b/cgroup_sched/framework/sched_controller/include/cgroup_event_handler.h new file mode 100644 index 00000000..a3eaa6ff --- /dev/null +++ b/cgroup_sched/framework/sched_controller/include/cgroup_event_handler.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 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 CGROUP_EVENT_HANDLER_H +#define CGROUP_EVENT_HANDLER_H + +#include +#include "event_handler.h" +#include "supervisor.h" +#include "wm_common.h" + +namespace OHOS { +namespace ResourceSchedule { + +using OHOS::AppExecFwk::EventHandler; +using OHOS::AppExecFwk::EventRunner; +using OHOS::Rosen::WindowType; + +namespace { + const int INNER_EVENT_ID_REG_WINDOW_FOCUS_STATE = 0; + const int DELAYED_REGISTER_DURATION = 500; +} + +class CgroupEventHandler : public EventHandler { +public: + CgroupEventHandler(const std::shared_ptr &runner); + ~CgroupEventHandler(); + virtual void ProcessEvent(const AppExecFwk::InnerEvent::Pointer& event) override; + void SetSupervisor(std::shared_ptr supervisor); + void HandleForegroundApplicationChanged(uid_t uid, std::string bundleName, int32_t state); + void HandleAbilityStateChanged(uid_t uid, pid_t pid, std::string bundleName, std::string abilityName, sptr token, int32_t abilityState); + void HandleExtensionStateChanged(uid_t uid, pid_t pid, std::string bundleName, std::string abilityName, sptr token, int32_t extensionState); + void HandleProcessCreated(uid_t uid, pid_t pid, std::string bundleName); + void HandleProcessDied(uid_t uid, pid_t pid, std::string bundleName); + void HandleTransientTaskStart(uid_t uid, pid_t pid, std::string packageName); + void HandleTransientTaskEnd(uid_t uid, pid_t pid, std::string packageName); + void HandleContinuousTaskStart(uid_t uid, pid_t pid, std::string abilityName); + void HandleContinuousTaskCancel(uid_t uid, pid_t pid, std::string abilityName); + void HandleWindowFocusChange(int32_t windowId, int32_t displayId, WindowType windowType, sptr token); + void HandleFocusedWindow(uint32_t windowId, sptr abilityToken, WindowType windowType, int32_t displayId); + void HandleUnfocusedWindow(uint32_t windowId, sptr abilityToken, WindowType windowType, int32_t displayId); +private: + std::shared_ptr supervisor_; +}; +} // namespace ResourceSchedule +} // namespace OHOS + +#endif // CGROUP_EVENT_HANDLER_H diff --git a/cgroup_sched/framework/sched_controller/include/continuous_task_observer.h b/cgroup_sched/framework/sched_controller/include/continuous_task_observer.h new file mode 100644 index 00000000..b8dac57d --- /dev/null +++ b/cgroup_sched/framework/sched_controller/include/continuous_task_observer.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 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 CONTINUOUS_TASK_OBSERVER_H +#define CONTINUOUS_TASK_OBSERVER_H + +#include "../../../dummy_adaption/background_task_mgr/continuous_task_dummy.h" + +namespace OHOS { +namespace ResourceSchedule { +using OHOS::BackgroundTaskMgr::ContinuousTaskEventSubscriber; +using OHOS::BackgroundTaskMgr::ContinuousTaskConstant; +using OHOS::BackgroundTaskMgr::ContinuousTaskEventData; + +class ContinuousTaskObserver : public ContinuousTaskEventSubscriber { +public: + ContinuousTaskObserver() {}; + ~ContinuousTaskObserver() {}; + + void OnSubscribeResult(ContinuousTaskConstant::SubscribeResult result); + void OnUnsubscribeResult(ContinuousTaskConstant::SubscribeResult result); + void OnContinuousTaskStart(const std::shared_ptr &eventData); + void OnContinuousTaskCancel(const std::shared_ptr &eventData); + void OnDied(); + +private: + void HandleContinuousTaskStart(uid_t uid, pid_t pid, std::string abilityName); + void HandleContinuousTaskCancel(uid_t uid, pid_t pid, std::string abilityName); + + inline bool ValidateTransientTaskAppInfo(const std::shared_ptr& eventData) const + { + return eventData->GetCreatorUid() > 0 && eventData->GetCreatorPid() >= 0 + && eventData->GetAbilityName().size() > 0; + } + + inline std::string PackPayload(const std::shared_ptr& eventData) const + { + return std::to_string(eventData->GetCreatorPid()) + "," + std::to_string(eventData->GetCreatorUid()) + "," + eventData->GetAbilityName(); + } +}; + +} // namespace ResourceSchedule +} // namespace OHOS +#endif // CONTINUOUS_TASK_OBSERVER_H diff --git a/cgroup_sched/framework/sched_controller/include/sched_controller.h b/cgroup_sched/framework/sched_controller/include/sched_controller.h new file mode 100644 index 00000000..fa3fc6a7 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/include/sched_controller.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2021 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 SCHED_CONTROLLER_H +#define SCHED_CONTROLLER_H + +#include +#include +#include "hilog/log.h" + +#include "app_mgr_interface.h" +#include "window_state_observer.h" + +namespace OHOS { +namespace ResourceSchedule { + +class RmsApplicationStateObserver; +class TransientTaskObserver; +class ContinuousTaskObserver; +class Supervisor; +class Application; +class ProcessRecord; +class CgroupAdjuster; +class CgroupEventHandler; +enum class AdjustSource; + +class SchedController { +public: + static SchedController& GetInstance(); + + void Init(); + void Deinit(); + void RegisterStateObservers(); + void UnregisterStateObservers(); + void AdjustProcessGroup(Application &app, ProcessRecord &pr, AdjustSource source); + void AdjustAllProcessGroup(Application &app, AdjustSource source); + int GetProcessGroup(pid_t pid); + void SubscribeWindowState(); + + const inline std::shared_ptr GetCgroupEventHandler() const { + return cgHandler_; + } + + const inline std::shared_ptr GetSupervisor() const { + return supervisor_; + } + +private: + SchedController() = default; + ~SchedController() = default; + + SchedController(const SchedController&) = delete; + SchedController& operator=(const SchedController &) = delete; + SchedController(SchedController&&) = delete; + SchedController& operator=(SchedController&&) = delete; + + std::shared_ptr cgHandler_; + std::shared_ptr cgAdjuster_; + std::shared_ptr supervisor_; + std::shared_ptr appStateObserver_; + std::shared_ptr transientTaskObserver_; + std::shared_ptr continuousTaskObserver_; + sptr windowStateObserver_; + + inline void InitCgroupHandler(); + inline void InitCgroupAdjuster(); + inline void InitSupervisor(); + inline void SubscribeAppState(); + inline void SubscribeTransientTask(); + inline void SubscribeContinuousTask(); +}; + +} // namespace ResourceSchedule +} // namespace OHOS +#endif // SCHED_CONTROLLER_H diff --git a/cgroup_sched/framework/sched_controller/include/supervisor.h b/cgroup_sched/framework/sched_controller/include/supervisor.h new file mode 100644 index 00000000..81ef0a16 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/include/supervisor.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021 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 SUPERVISOR_H +#define SUPERVISOR_H + +#include +#include +#include +#include + +#include "iremote_object.h" +#include "sched_policy.h" +#include "app_mgr_constants.h" + +namespace OHOS { +namespace ResourceSchedule { + +using OHOS::AppExecFwk::ApplicationState; +using OHOS::AppExecFwk::AbilityState; +using OHOS::AppExecFwk::ExtensionState; +using OHOS::ResourceSchedule::CgroupSetting::SchedPolicy; + +class ProcessRecord { +public: + ProcessRecord(); + ProcessRecord(uid_t uid, pid_t pid) : uid_(uid), pid_(pid) {}; + ProcessRecord(uid_t uid, pid_t pid, std::string name) : uid_(uid), pid_(pid), name_(name) {}; + ~ProcessRecord() = default; + + inline pid_t GetPid() const + { + return pid_; + } + + inline uid_t GetUid() const + { + return uid_; + } + + inline std::string GetName() const + { + return name_; + } + + SchedPolicy lastSchedGroup_ = SchedPolicy::SP_DEFAULT; + SchedPolicy curSchedGroup_ = SchedPolicy::SP_DEFAULT; + SchedPolicy setSchedGroup_ = SchedPolicy::SP_DEFAULT; + bool runningTransientTask_ = false; + bool runningContinuousTask_ = false; + bool focused_ = false; + int32_t abilityState_ = static_cast(AbilityState::ABILITY_STATE_TERMINATED); + int32_t extensionState_ = static_cast(ExtensionState::EXTENSION_STATE_TERMINATED); + int32_t windowType_; + sptr token_ = nullptr; + +private: + uid_t uid_; + pid_t pid_; + std::string name_; +}; + +class Application { +public: + Application(); + Application(uid_t uid, std::string name) : uid_(uid), name_(name) {}; + ~Application() = default; + + std::shared_ptr AddProcessRecord(std::shared_ptr pr); + std::shared_ptr RemoveProcessRecord(pid_t pid); + std::shared_ptr GetProcessRecord(pid_t pid); + std::shared_ptr GetProcessRecordNonNull(pid_t pid, std::string name); + std::shared_ptr FindProcessRecord(sptr token_); + + inline uid_t GetUid() const + { + return uid_; + } + + inline std::string GetName() const + { + return name_; + } + + inline std::map> GetPidsMap() const + { + return pidsMap_; + } + + std::shared_ptr focusedProcess_ = nullptr; + SchedPolicy lastSchedGroup_ = SchedPolicy::SP_DEFAULT; + SchedPolicy curSchedGroup_ = SchedPolicy::SP_DEFAULT; + SchedPolicy setSchedGroup_ = SchedPolicy::SP_DEFAULT; + int32_t state_ = static_cast(ApplicationState::APP_STATE_TERMINATED); + +private: + uid_t uid_; + std::string name_; + std::map> pidsMap_; + +}; + +class Supervisor { +public: + std::shared_ptr GetAppRecord(int32_t uid); + std::shared_ptr GetAppRecordNonNull(int32_t uid, std::string bundleName); + std::shared_ptr FindProcessRecord(pid_t pid); + void SearchAbilityToken(std::shared_ptr &app, std::shared_ptr &procRecord, sptr token); + +private: + std::map> uidsMap_; +}; +} // namespace ResourceSchedule +} // namespace OHOS +#endif // SUPERVISOR_H diff --git a/cgroup_sched/framework/sched_controller/include/transient_task_observer.h b/cgroup_sched/framework/sched_controller/include/transient_task_observer.h new file mode 100644 index 00000000..331708b6 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/include/transient_task_observer.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 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 TRANSIENT_TASK_OBSERVER_H +#define TRANSIENT_TASK_OBSERVER_H + +#include +#include "transient_task_app_info.h" +#include "background_task_subscriber.h" + +namespace OHOS { +namespace ResourceSchedule { +using OHOS::BackgroundTaskMgr::BackgroundTaskSubscriber; +using OHOS::BackgroundTaskMgr::TransientTaskAppInfo; + +class TransientTaskObserver : public BackgroundTaskSubscriber { +public: + TransientTaskObserver() {}; + ~TransientTaskObserver() {}; + + void OnTransientTaskStart(const std::shared_ptr& info); + void OnTransientTaskEnd(const std::shared_ptr& info); + +private: + void HandleTransientTaskStart(uid_t uid, pid_t pid, std::string packageName); + void HandleTransientTaskEnd(uid_t uid, pid_t pid, std::string packageName); + + inline bool ValidateTransientTaskAppInfo(const std::shared_ptr& info) const + { + return info->GetUid() > 0 && info->GetPid() >= 0 + && info->GetPackageName().size() > 0; + } + + inline std::string PackPayload(const std::shared_ptr& info) const + { + return std::to_string(info->GetPid()) + "," + std::to_string(info->GetUid()) + "," + info->GetPackageName(); + } +}; + +} // namespace ResourceSchedule +} // namespace OHOS +#endif // TRANSIENT_TASK_OBSERVER_H diff --git a/cgroup_sched/framework/sched_controller/include/window_state_observer.h b/cgroup_sched/framework/sched_controller/include/window_state_observer.h new file mode 100644 index 00000000..25194ab5 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/include/window_state_observer.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 WINDOW_STATE_OBSERVER_H +#define WINDOW_STATE_OBSERVER_H + +#include +#include "iremote_object.h" +#include "window_manager.h" +#include "wm_common.h" + +namespace OHOS { +namespace ResourceSchedule { + +using OHOS::Rosen::IFocusChangedListener; +using OHOS::Rosen::WindowType; + +class WindowStateObserver : public IFocusChangedListener { +public: + void OnFocused(uint32_t windowId, sptr abilityToken, + WindowType windowType, int32_t displayId) override; + void OnUnfocused(uint32_t windowId, sptr abilityToken, + WindowType windowType, int32_t displayId) override; +}; + +} // namespace ResourceSchedule +} // namespace OHOS +#endif // WINDOW_STATE_OBSERVER_H diff --git a/cgroup_sched/framework/sched_controller/sched_controller.cpp b/cgroup_sched/framework/sched_controller/sched_controller.cpp new file mode 100644 index 00000000..0a0ec662 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/sched_controller.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2021 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 "sched_controller.h" + +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "app_state_observer.h" +#include "background_task_mgr_helper.h" +#include "cgroup_adjuster.h" +#include "cgroup_event_handler.h" +#include "continuous_task_observer.h" +#include "cgroup_sched_common.h" +#include "cgroup_sched_log.h" +#include "ressched_utils.h" +#include "supervisor.h" +#include "transient_task_observer.h" +#include "window_state_observer.h" + +namespace OHOS { +namespace ResourceSchedule { + +using OHOS::ResourceSchedule::CgroupSetting::SchedPolicy; + +namespace { + const std::string CG_HANDLER_THREAD = "CgroupEventHandler"; + constexpr HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_RMS, "SchedController"}; +} + +OHOS::sptr GetAppManagerInstance() +{ + OHOS::sptr systemAbilityManager = + OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + OHOS::sptr object = systemAbilityManager->GetSystemAbility(OHOS::APP_MGR_SERVICE_ID); + return OHOS::iface_cast(object); +} + +SchedController& SchedController::GetInstance() +{ + static auto instance = new SchedController(); + return *instance; +} + +void SchedController::Init() +{ + ChronoScope cs("Init SchedController."); + // Init supervisor which contains cached data for ccgroup controller. + InitSupervisor(); + // Init cgroup handler thread + InitCgroupHandler(); + // Init cgroup adjuster thread + InitCgroupAdjuster(); +} + +void SchedController::Deinit() +{ + if (cgHandler_ != nullptr) { + cgHandler_->RemoveAllEvents(); + cgHandler_ = nullptr; + } + if (supervisor_ != nullptr) { + supervisor_ = nullptr; + } +} + +void SchedController::RegisterStateObservers() +{ + // register callback observers for app state + SubscribeAppState(); + // register callback observers for background task + SubscribeTransientTask(); + SubscribeContinuousTask(); + // register callback observers for window state + auto event = AppExecFwk::InnerEvent::Get(INNER_EVENT_ID_REG_WINDOW_FOCUS_STATE); + cgHandler_->SendEvent(event, DELAYED_REGISTER_DURATION); +} + +void SchedController::UnregisterStateObservers() +{ + sptr appManager = GetAppManagerInstance(); + if (appManager != nullptr && appStateObserver_ != nullptr) { + int32_t err = appManager->UnregisterApplicationStateObserver(appStateObserver_.get()); + if (err == 0) { + CGS_LOGI("UnregisterApplicationStateObserver success."); + } else { + CGS_LOGE("UnregisterApplicationStateObserver failed. err:%{public}d", err); + } + } + appStateObserver_ = nullptr; + + if (transientTaskObserver_ != nullptr) { + OHOS::BackgroundTaskMgr::BackgroundTaskMgrHelper::UnsubscribeBackgroundTask(*transientTaskObserver_); + } + transientTaskObserver_ = nullptr; + + if (continuousTaskObserver_ != nullptr) { + OHOS::BackgroundTaskMgr::BackgroundTaskMgrHelper_::RequestUnsubscribe(*continuousTaskObserver_); + } + continuousTaskObserver_ = nullptr; + + if (windowStateObserver_ != nullptr) { + // unregister windowStateObserver_ + OHOS::Rosen::WindowManager::GetInstance().UnregisterFocusChangedListener(windowStateObserver_); + } + windowStateObserver_ = nullptr; +} + +void SchedController::AdjustProcessGroup(Application &app, ProcessRecord &pr, AdjustSource source) +{ + if (cgAdjuster_ == nullptr) { + CGS_LOGE("SchedController is disabled due to null cgAdjuster_"); + return; + } + cgAdjuster_->AdjustProcessGroup(app, pr, source); +} + +void SchedController::AdjustAllProcessGroup(Application &app, AdjustSource source) +{ + if (cgAdjuster_ == nullptr) { + CGS_LOGE("SchedController is disabled due to null cgAdjuster_"); + return; + } + cgAdjuster_->AdjustAllProcessGroup(app, source); +} + +int SchedController::GetProcessGroup(pid_t pid) +{ + if (supervisor_ == nullptr) { + CGS_LOGE("SchedController::GetProcessCgroup, supervisor nullptr."); + return VALUE_INT(SchedPolicy::SP_DEFAULT); + } + std::shared_ptr pr = supervisor_->FindProcessRecord(pid); + return pr == nullptr ? VALUE_INT(SchedPolicy::SP_DEFAULT) : VALUE_INT(pr->curSchedGroup_); +} + +inline void SchedController::InitCgroupHandler() +{ + cgHandler_ = std::make_shared(OHOS::AppExecFwk::EventRunner::Create(CG_HANDLER_THREAD)); + cgHandler_->SetSupervisor(supervisor_); +} + +inline void SchedController::InitCgroupAdjuster() +{ + cgAdjuster_ = std::make_shared(); + cgAdjuster_->InitAdjuster(); +} + +inline void SchedController::InitSupervisor() +{ + supervisor_ = std::make_shared(); +} + +inline void SchedController::SubscribeAppState() +{ + sptr appManager = GetAppManagerInstance(); + if (appManager == nullptr) { + CGS_LOGE("%{public}s app manager nullptr!", __func__); + return; + } + appStateObserver_ = std::make_shared(); + int32_t err = appManager->RegisterApplicationStateObserver(appStateObserver_.get()); + if (err == 0) { + CGS_LOGI("RegisterApplicationStateObserver success."); + } else { + CGS_LOGE("RegisterApplicationStateObserver failed. err:%{public}d", err); + } +} + +inline void SchedController::SubscribeTransientTask() +{ + transientTaskObserver_ = std::make_shared(); + bool ret = OHOS::BackgroundTaskMgr::BackgroundTaskMgrHelper::SubscribeBackgroundTask(*transientTaskObserver_); + if (ret) { + CGS_LOGI("Register TransientTaskObserver success."); + } else { + CGS_LOGE("Register TransientTaskObserver failed."); + } +} + +inline void SchedController::SubscribeContinuousTask() +{ + continuousTaskObserver_ = std::make_shared(); + OHOS::BackgroundTaskMgr::BackgroundTaskMgrHelper_::RequestSubscribe(*continuousTaskObserver_); +} + +void SchedController::SubscribeWindowState() +{ + windowStateObserver_ = new WindowStateObserver(); + OHOS::Rosen::WindowManager::GetInstance().RegisterFocusChangedListener(windowStateObserver_); +} + +extern "C" void CgroupSchedInit() +{ + SchedController::GetInstance().Init(); + SchedController::GetInstance().RegisterStateObservers(); +} + +extern "C" void CgroupSchedDeinit() +{ + SchedController::GetInstance().Deinit(); + SchedController::GetInstance().UnregisterStateObservers(); +} + +extern "C" int GetProcessGroup(pid_t pid) +{ + return SchedController::GetInstance().GetProcessGroup(pid); +} + +} // namespace ResourceSchedule +} // namespace OHOS diff --git a/cgroup_sched/framework/sched_controller/supervisor.cpp b/cgroup_sched/framework/sched_controller/supervisor.cpp new file mode 100644 index 00000000..de252b55 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/supervisor.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2021 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 "supervisor.h" + +namespace OHOS { +namespace ResourceSchedule { + +std::shared_ptr Application::AddProcessRecord(std::shared_ptr pr) +{ + if (pr != nullptr) { + pidsMap_[pr->GetPid()] = pr; + } + return pr; +} + +std::shared_ptr Application::RemoveProcessRecord(pid_t pid) +{ + auto iter = pidsMap_.find(pid); + if (iter == pidsMap_.end()) { + return nullptr; + } + pidsMap_.erase(iter); + return iter->second; +} + +std::shared_ptr Application::GetProcessRecord(pid_t pid) +{ + if (pidsMap_.find(pid) == pidsMap_.end()) { + return nullptr; + } + return pidsMap_[pid]; +} + +std::shared_ptr Application::GetProcessRecordNonNull(pid_t pid, std::string name) +{ + if (pidsMap_.find(pid) == pidsMap_.end()) { + auto pr = std::make_shared(this->GetUid(), pid, name); + this->AddProcessRecord(pr); + return pr; + } + return pidsMap_[pid]; +} + +std::shared_ptr Application::FindProcessRecord(sptr token_) +{ + for (auto iter = pidsMap_.begin(); iter != pidsMap_.end(); iter++) + { + auto pr = iter->second; + if (pr->token_ == token_) { + return pr; + } + } + return nullptr; +} + +std::shared_ptr Supervisor::GetAppRecord(int32_t uid) +{ + if (uidsMap_.find(uid) == uidsMap_.end()) { + return nullptr; + } + return uidsMap_[uid]; +} + +std::shared_ptr Supervisor::GetAppRecordNonNull(int32_t uid, std::string bundleName) +{ + if (uidsMap_.find(uid) == uidsMap_.end()) { + auto app = std::make_shared(uid, bundleName); + uidsMap_[uid] = app; + return app; + } + return uidsMap_[uid]; +} + +std::shared_ptr Supervisor::FindProcessRecord(pid_t pid) +{ + std::shared_ptr pr = nullptr; + for (auto iter = uidsMap_.begin(); iter != uidsMap_.end(); iter++) + { + auto app = iter->second; + pr = app->GetProcessRecord(pid); + if (pr != nullptr) { + break; + } + } + return pr; +} + +void Supervisor::SearchAbilityToken(std::shared_ptr &application, std::shared_ptr &procRecord, sptr token) +{ + std::shared_ptr pr = nullptr; + for (auto iter = uidsMap_.begin(); iter != uidsMap_.end(); iter++) + { + auto app = iter->second; + pr = app->FindProcessRecord(token); + if (pr != nullptr) { + application = app; + procRecord = pr; + break; + } + } +} + +} // namespace ResourceSchedule +} // namespace OHOS diff --git a/cgroup_sched/framework/sched_controller/transient_task_observer.cpp b/cgroup_sched/framework/sched_controller/transient_task_observer.cpp new file mode 100644 index 00000000..37058284 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/transient_task_observer.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 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 "transient_task_observer.h" + +#include "cgroup_sched_log.h" +#include "sched_controller.h" +#include "cgroup_event_handler.h" +#include "ressched_utils.h" +#include "res_type.h" + +namespace OHOS { +namespace ResourceSchedule { + +namespace { + constexpr HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_RMS, "TransientTaskObserver"}; +} + +void TransientTaskObserver::OnTransientTaskStart(const std::shared_ptr& info) +{ + if (!ValidateTransientTaskAppInfo(info)) { + return; + } + /* class TransientTaskAppInfo {std::string& GetPackageName(); int32_t GetUid(); int32_t GetPid();} */ + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, info] { + cgHander->HandleTransientTaskStart(info->GetUid(), info->GetPid(), info->GetPackageName()); + }); + } + + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_TRANSIENT_TASK, 0, PackPayload(info)); +} + +void TransientTaskObserver::OnTransientTaskEnd(const std::shared_ptr& info) +{ + if (!ValidateTransientTaskAppInfo(info)) { + CGS_LOGE("%{public}s failed, invalid app info!", __func__); + return; + } + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, info] { + cgHander->HandleTransientTaskEnd(info->GetUid(), info->GetPid(), info->GetPackageName()); + }); + } + + ResSchedUtils::GetInstance().ReportDataInProcess(ResType::RES_TYPE_TRANSIENT_TASK, 1, PackPayload(info)); +} + +} // namespace ResourceSchedule +} // namespace OHOS diff --git a/cgroup_sched/framework/sched_controller/window_state_observer.cpp b/cgroup_sched/framework/sched_controller/window_state_observer.cpp new file mode 100644 index 00000000..9d732079 --- /dev/null +++ b/cgroup_sched/framework/sched_controller/window_state_observer.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 "window_state_observer.h" + +#include "cgroup_sched_log.h" +#include "cgroup_event_handler.h" +#include "res_type.h" +#include "sched_controller.h" + +namespace OHOS { +namespace ResourceSchedule { + +void WindowStateObserver::OnFocused(uint32_t windowId, sptr abilityToken, WindowType windowType, int32_t displayId) +{ + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, windowId, abilityToken, windowType, displayId] { + cgHander->HandleFocusedWindow(windowId, abilityToken, windowType, displayId); + }); + } +} + +void WindowStateObserver::OnUnfocused(uint32_t windowId, sptr abilityToken, WindowType windowType, int32_t displayId) +{ + auto cgHander = SchedController::GetInstance().GetCgroupEventHandler(); + if (cgHander != nullptr) { + cgHander->PostTask([cgHander, windowId, abilityToken, windowType, displayId] { + cgHander->HandleUnfocusedWindow(windowId, abilityToken, windowType, displayId); + }); + } +} + +} // namespace OHOS +} // namespace ResourceSchedule diff --git a/cgroup_sched/framework/utils/include/ressched_utils.h b/cgroup_sched/framework/utils/include/ressched_utils.h new file mode 100644 index 00000000..0c17fad2 --- /dev/null +++ b/cgroup_sched/framework/utils/include/ressched_utils.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 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 RES_SCHED_UTILS_H +#define RES_SCHED_UTILS_H + +#include +#include "sys/types.h" + +namespace OHOS { +namespace ResourceSchedule { + +using ReportDataFunc = void (*)(uint32_t resType, int64_t value, const std::string& payload); + +class ResSchedUtils { +public: + static ResSchedUtils& GetInstance(); + void ReportDataInProcess(uint32_t resType, int64_t value, const std::string& payload); + +private: + ResSchedUtils() + { + if (reportFunc_ == nullptr) { + LoadUtils(); + } + } + ~ResSchedUtils() + { + reportFunc_ = nullptr; + } + void LoadUtils(); + + ResSchedUtils(const ResSchedUtils&) = delete; + ResSchedUtils& operator=(const ResSchedUtils &) = delete; + ResSchedUtils(ResSchedUtils&&) = delete; + ResSchedUtils& operator=(ResSchedUtils&&) = delete; + + ReportDataFunc reportFunc_ = nullptr; +}; + +} // namespace ResourceSchedule +} // namespace OHOS +#endif // RES_SCHED_UTILS_H diff --git a/cgroup_sched/framework/utils/ressched_utils.cpp b/cgroup_sched/framework/utils/ressched_utils.cpp new file mode 100644 index 00000000..b9a4faa2 --- /dev/null +++ b/cgroup_sched/framework/utils/ressched_utils.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 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 "ressched_utils.h" +#include "cgroup_sched_log.h" +#include + +namespace OHOS { +namespace ResourceSchedule { + +namespace { + const std::string RES_SCHED_CLIENT_SO = "/system/lib/libressched_client.z.so"; + constexpr HiviewDFX::HiLogLabel LOG_LABEL = {LOG_CORE, LOG_TAG_DOMAIN_ID_RMS, "ResSchedUtils"}; +} + +ResSchedUtils& ResSchedUtils::GetInstance() +{ + static auto instance = new ResSchedUtils(); + return *instance; +} + +void ResSchedUtils::LoadUtils() +{ + auto handle = dlopen(RES_SCHED_CLIENT_SO.c_str(), RTLD_NOW); + if (handle == nullptr) { + CGS_LOGE("%{public}s load %{public}s failed!", __func__, RES_SCHED_CLIENT_SO.c_str()); + return; + } + + auto func = reinterpret_cast(dlsym(handle, "ReportDataInProcess")); + if (func == nullptr) { + CGS_LOGE("%{public}s load function:ReportDataInProcess failed!", __func__); + dlclose(handle); + return; + } + reportFunc_ = func; +} + +void ResSchedUtils::ReportDataInProcess(uint32_t resType, int64_t value, const std::string& payload) +{ + if (reportFunc_ == nullptr) { + CGS_LOGE("%{public}s failed, function nullptr.", __func__); + return; + } + reportFunc_(resType, value, payload); +} + +} // namespace ResourceSchedule +} // namespace OHOS diff --git a/cgroup_sched/interfaces/innerkits/include/cgroup_sched.h b/cgroup_sched/interfaces/innerkits/include/cgroup_sched.h new file mode 100644 index 00000000..1c2831f0 --- /dev/null +++ b/cgroup_sched/interfaces/innerkits/include/cgroup_sched.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 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 CGROUP_SCHED_H +#define CGROUP_SCHED_H + +#include "sys/types.h" + +namespace OHOS { +namespace ResourceSchedule { + +extern "C" void CgroupSchedInit(); +extern "C" void CgroupSchedDeinit(); +extern "C" int GetProcessGroup(pid_t pid); + +} // namespace ResourceSchedule +} // namespace OHOS + +#endif // CGROUP_SCHED_H \ No newline at end of file diff --git a/cgroup_sched/profiles/BUILD.gn b/cgroup_sched/profiles/BUILD.gn new file mode 100644 index 00000000..a15179e4 --- /dev/null +++ b/cgroup_sched/profiles/BUILD.gn @@ -0,0 +1,28 @@ +# Copyright (c) 2022 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("//build/ohos.gni") +import("//build/ohos/sa_profile/sa_profile.gni") + +ohos_prebuilt_etc("process_group_config") { + if (device_name == "rk3568") { + source = "rk3658/cgroup_action_config.json" + install_enable = true + } else { + source = "others/cgroup_action_config.json" + install_enable = true + } + module_install_dir = "etc/process_group" + part_name = "resource_schedule_service" + subsystem_name = "resourceschedule" +} \ No newline at end of file diff --git a/cgroup_sched/profiles/others/cgroup_action_config.json b/cgroup_sched/profiles/others/cgroup_action_config.json new file mode 100644 index 00000000..fb91406b --- /dev/null +++ b/cgroup_sched/profiles/others/cgroup_action_config.json @@ -0,0 +1,26 @@ +{ + "Cgroups": [ + { + "controller": "cpu", + "path": "/dev/cpuctl", + "sched_policy": { + "sp_background": "background", + "sp_foreground": "foreground", + "sp_system": "system", + "sp_top_app": "top-app", + "sp_root": "root" + } + }, + { + "controller": "cpuset", + "path": "/dev/cpuset", + "sched_policy": { + "sp_background": "background", + "sp_foreground": "foreground", + "sp_system": "system", + "sp_top_app": "top-app", + "sp_root": "root" + } + } + ] + } \ No newline at end of file diff --git a/cgroup_sched/profiles/rk3658/cgroup_action_config.json b/cgroup_sched/profiles/rk3658/cgroup_action_config.json new file mode 100644 index 00000000..59e449f6 --- /dev/null +++ b/cgroup_sched/profiles/rk3658/cgroup_action_config.json @@ -0,0 +1,26 @@ +{ + "Cgroups": [ + { + "controller": "cpuctl", + "path": "/dev/cpuctl", + "sched_policy": { + "sp_default": "", + "sp_background": "background", + "sp_foreground": "foreground", + "sp_system": "system", + "sp_top_app": "top-app" + } + }, + { + "controller": "cpuset", + "path": "/dev/cpuset", + "sched_policy": { + "sp_default": "", + "sp_background": "background", + "sp_foreground": "foreground", + "sp_system": "system", + "sp_top_app": "top-app" + } + } + ] +} \ No newline at end of file diff --git a/ressched/bundle.json b/ressched/bundle.json index 5701cdcb..1813e384 100644 --- a/ressched/bundle.json +++ b/ressched/bundle.json @@ -40,7 +40,11 @@ "//foundation/resourceschedule/resource_schedule_service/ressched/profile:ressched_plugin_config", "//foundation/resourceschedule/resource_schedule_service/ressched/profile:ressched_plugin_switch", "//foundation/resourceschedule/resource_schedule_service/ressched/sa_profile:ressched_sa_profile", - "//foundation/resourceschedule/resource_schedule_service/ressched/etc/init:resource_schedule_service.cfg" + "//foundation/resourceschedule/resource_schedule_service/ressched/etc/init:resource_schedule_service.cfg", + "//foundation/resourceschedule/resource_schedule_service/ressched/sa_profile:ressched_sa_profile", + "//foundation/resourceschedule/resource_schedule_service/cgroup_sched/framework:cgroup_sched", + "//foundation/resourceschedule/resource_schedule_service/cgroup_sched/profiles:process_group_config", + "//foundation/resourceschedule/resource_schedule_service/cgroup_sched/framework/process_group:libprocess_group" ], "inner_kits": [ { @@ -62,4 +66,4 @@ ] } } -} \ No newline at end of file +} diff --git a/ressched/etc/init/resource_schedule_service.cfg b/ressched/etc/init/resource_schedule_service.cfg index d356fef0..c633d87e 100644 --- a/ressched/etc/init/resource_schedule_service.cfg +++ b/ressched/etc/init/resource_schedule_service.cfg @@ -9,6 +9,7 @@ "services" : [{ "name" : "resource_schedule_service", "path" : ["/system/bin/sa_main", "/system/profile/resource_schedule_service.xml"], + "importance" : -20, "uid" : "root", "gid" : ["root", "shell"] } diff --git a/ressched/interfaces/innerkits/ressched_client/include/res_type.h b/ressched/interfaces/innerkits/ressched_client/include/res_type.h index 9cfe641f..87da4732 100644 --- a/ressched/interfaces/innerkits/ressched_client/include/res_type.h +++ b/ressched/interfaces/innerkits/ressched_client/include/res_type.h @@ -24,6 +24,22 @@ namespace ResType { enum : uint32_t { // screen status, value 0 means screen off, value 1 means screen on, else are invalid. RES_TYPE_SCREEN_STATUS, + // app state change event; value means app state; payload:uid,bundleName + RES_TYPE_APP_STATE_CHANGE, + // ability state change event; value means ability state; payload:pid,uid,bundleName + RES_TYPE_ABILITY_STATE_CHANGE, + // extension state change event; value means extension state; payload:pid,uid,bundleName + RES_TYPE_EXTENSION_STATE_CHANGE, + // process state event; value 0:created, 1:died; payload:pid,uid,bundleName + RES_TYPE_PROCESS_STATE_CHANGE, + // window focused event; value 0:focused, 1:unfocused; payload:pid,uid,bundleName,windowId,windowType,displayId + RES_TYPE_WINDOW_FOCUS, + // transient task event; value 0:start, 1:finish; payload:pid,uid,bundleName + RES_TYPE_TRANSIENT_TASK, + // continuous task event; value 0:start, 1:finish; payload:pid,uid,abilityName + RES_TYPE_CONTINUOUS_TASK, + // cgroup change event; value means nothing; payload:pid,uid,name,oldGroup,newGroup + RES_TYPE_CGROUP_ADJUSTER, }; } } // namespace ResourceSchedule diff --git a/ressched/interfaces/innerkits/ressched_client/src/res_sched_client.cpp b/ressched/interfaces/innerkits/ressched_client/src/res_sched_client.cpp index 0b2b5e64..3c815618 100644 --- a/ressched/interfaces/innerkits/ressched_client/src/res_sched_client.cpp +++ b/ressched/interfaces/innerkits/ressched_client/src/res_sched_client.cpp @@ -93,5 +93,11 @@ void ResSchedClient::ResSchedDeathRecipient::OnRemoteDied(const wptr