• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <cstdint>
17 
18 #include <chrono>
19 #include <memory>
20 #include <mutex>
21 #include <optional>
22 #include <string>
23 #include <utility>
24 
25 #include <unistd.h>
26 
27 #include "plugin_mgr.h"
28 #include "res_sched_log.h"
29 #include "event_handler.h"
30 #include "event_runner.h"
31 
32 #include "latency_control/inetwork_latency_switcher.h"
33 #include "latency_control/network_latency_controller.h"
34 #include "latency_control/noop_network_latency_switcher.h"
35 #include "latency_control/pmqos_network_latency_switcher.h"
36 
37 namespace OHOS::ResourceSchedule {
38 namespace {
39     const std::string NET_LATENCY_TIMER_NAME = "netLatTimer";
40     const std::chrono::duration TIMEOUT = std::chrono::seconds(60); // 1 minute timeout
41 }
42 
Init()43 void NetworkLatencyController::Init()
44 {
45     // use PMQoS switch if available
46     int err = access(PmqosNetworkLatencySwitcher::PMQOS_PATH.data(), W_OK);
47     if (!err) {
48         RESSCHED_LOGI("%{public}s: using pmqos latency switcher", __func__);
49         Init(std::make_unique<PmqosNetworkLatencySwitcher>());
50         return;
51     }
52 
53     // Another latency switchers can be implemented if required.
54     // If nothing matched, use default object, which is noop switcher.
55     RESSCHED_LOGI("%{public}s: using default latency switcher", __func__);
56     Init(std::make_unique<NoopNetworkLatencySwitcher>());
57 }
58 
Init(std::unique_ptr<INetworkLatencySwitcher> sw)59 void NetworkLatencyController::Init(std::unique_ptr<INetworkLatencySwitcher> sw)
60 {
61     handler = std::make_shared<AppExecFwk::EventHandler>(
62         PluginMgr::GetInstance().GetRunner()
63     );
64     if (!handler) {
65         RESSCHED_LOGE("%{public}s: failed: cannot allocate event handler", __func__);
66         return;
67     }
68 
69     switcher = std::move(sw);
70 }
71 
HandleRequest(long long value,const std::string & identity)72 void NetworkLatencyController::HandleRequest(long long value, const std::string &identity)
73 {
74     if (!switcher || !handler) {
75         RESSCHED_LOGE("%{public}s: controller is not initialized", __func__);
76         return;
77     }
78 
79     switch (value) {
80         case NETWORK_LATENCY_REQUEST_LOW:
81             HandleAddRequest(identity);
82             break;
83         case NETWORK_LATENCY_REQUEST_NORMAL:
84             HandleDelRequest(identity);
85             break;
86         default:
87             RESSCHED_LOGW("%{public}s: invalid value: %{public}lld", __func__, value);
88             return;
89     }
90 }
91 
HandleAddRequest(const std::string & identity)92 void NetworkLatencyController::HandleAddRequest(const std::string &identity)
93 {
94     // cancel auto disable task first
95     handler->RemoveTask(identity);
96     std::unique_lock<std::mutex> lk(mtx);
97 
98     RESSCHED_LOGD("%{public}s: add new request from %{public}s", __func__, identity.c_str());
99     AddRequest(identity);
100 
101     // set up the auto disable timer
102     handler->PostTask(
103         [this, identity] { AutoDisableTask(identity); },
104         identity, // use the identity as a key to manage this task
105         std::chrono::duration_cast<std::chrono::milliseconds>(TIMEOUT).count()
106     );
107 }
108 
HandleDelRequest(const std::string & identity)109 void NetworkLatencyController::HandleDelRequest(const std::string &identity)
110 {
111     // cancel auto disable task first
112     handler->RemoveTask(identity);
113     std::unique_lock<std::mutex> lk(mtx);
114 
115     RESSCHED_LOGD("%{public}s: delete request from %{public}s", __func__, identity.c_str());
116     DelRequest(identity);
117 }
118 
AddRequest(const std::string & identity)119 void NetworkLatencyController::AddRequest(const std::string &identity)
120 {
121     bool wasEmpty = requests.empty();
122     requests.insert(identity);
123 
124     // check whether it is the first request
125     if (wasEmpty) {
126         RESSCHED_LOGD("%{public}s: activating low latency", __func__);
127         switcher->LowLatencyOn();
128     }
129 }
130 
DelRequest(const std::string & identity)131 void NetworkLatencyController::DelRequest(const std::string &identity)
132 {
133     bool wasEmpty = requests.empty();
134     requests.erase(identity);
135 
136     // check whether is was the last request
137     if (!wasEmpty && requests.empty()) {
138         RESSCHED_LOGD("%{public}s: no callers left, restore normal latency", __func__);
139         switcher->LowLatencyOff();
140     }
141 }
142 
AutoDisableTask(const std::string & identity)143 void NetworkLatencyController::AutoDisableTask(const std::string &identity)
144 {
145     std::unique_lock<std::mutex> lk(mtx);
146 
147     RESSCHED_LOGD("%{public}s: identity %{public}s timed out", __func__, identity.c_str());
148     DelRequest(identity);
149 }
150 } // namespace OHOS::ResourceSchedule
151