1 /******************************************************************************
2 *
3 * Copyright 2021 Google, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #define LOG_TAG "BtGdWakelock"
20
21 #include "os/wakelock_manager.h"
22
23 #include <bluetooth/log.h>
24
25 #include <cerrno>
26 #include <mutex>
27
28 #include "os/internal/wakelock_native.h"
29
30 // TODO(b/369381361) Enfore -Wmissing-prototypes
31 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
32
33 namespace bluetooth {
34 namespace os {
35
36 using internal::WakelockNative;
37 using StatusCode = WakelockNative::StatusCode;
38
now_ms()39 uint64_t now_ms() {
40 struct timespec ts = {};
41 if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) {
42 log::error("unable to get current time: {}", strerror(errno));
43 return 0;
44 }
45 return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
46 }
47
48 const std::string WakelockManager::kBtWakelockId = "bluetooth_gd_timer";
49
50 // Wakelock statistics for the "bluetooth_timer"
51 struct WakelockManager::Stats {
52 bool is_acquired = false;
53 size_t acquired_count = 0;
54 size_t released_count = 0;
55 size_t acquired_errors = 0;
56 size_t released_errors = 0;
57 uint64_t min_acquired_interval_ms = 0;
58 uint64_t max_acquired_interval_ms = 0;
59 uint64_t last_acquired_interval_ms = 0;
60 uint64_t total_acquired_interval_ms = 0;
61 uint64_t last_acquired_timestamp_ms = 0;
62 uint64_t last_released_timestamp_ms = 0;
63 uint64_t last_reset_timestamp_ms = now_ms();
64 StatusCode last_acquired_error = StatusCode::SUCCESS;
65 StatusCode last_released_error = StatusCode::SUCCESS;
66
Resetbluetooth::os::WakelockManager::Stats67 void Reset() {
68 is_acquired = false;
69 acquired_count = 0;
70 released_count = 0;
71 acquired_errors = 0;
72 released_errors = 0;
73 min_acquired_interval_ms = 0;
74 max_acquired_interval_ms = 0;
75 last_acquired_interval_ms = 0;
76 total_acquired_interval_ms = 0;
77 last_acquired_timestamp_ms = 0;
78 last_released_timestamp_ms = 0;
79 last_reset_timestamp_ms = now_ms();
80 last_acquired_error = StatusCode::SUCCESS;
81 last_released_error = StatusCode::SUCCESS;
82 }
83
84 // Update the Bluetooth acquire wakelock statistics.
85 //
86 // This function should be called every time when the wakelock is acquired.
87 // |acquired_status| is the status code that was return when the wakelock was
88 // acquired.
UpdateAcquiredStatsbluetooth::os::WakelockManager::Stats89 void UpdateAcquiredStats(StatusCode acquired_status) {
90 const uint64_t just_now_ms = now_ms();
91 if (acquired_status != StatusCode::SUCCESS) {
92 acquired_errors++;
93 last_acquired_error = acquired_status;
94 }
95
96 if (is_acquired) {
97 return;
98 }
99
100 is_acquired = true;
101 acquired_count++;
102 last_acquired_timestamp_ms = just_now_ms;
103 }
104
105 // Update the Bluetooth release wakelock statistics.
106 //
107 // This function should be called every time when the wakelock is released.
108 // |released_status| is the status code that was return when the wakelock was
109 // released.
UpdateReleasedStatsbluetooth::os::WakelockManager::Stats110 void UpdateReleasedStats(StatusCode released_status) {
111 const uint64_t just_now_ms = now_ms();
112 if (released_status != StatusCode::SUCCESS) {
113 released_errors++;
114 last_released_error = released_status;
115 }
116
117 if (!is_acquired) {
118 return;
119 }
120
121 is_acquired = false;
122 released_count++;
123 last_released_timestamp_ms = just_now_ms;
124
125 // Compute the acquired interval and update the statistics
126 uint64_t delta_ms = just_now_ms - last_acquired_timestamp_ms;
127 if (delta_ms < min_acquired_interval_ms || released_count == 1) {
128 min_acquired_interval_ms = delta_ms;
129 }
130 if (delta_ms > max_acquired_interval_ms) {
131 max_acquired_interval_ms = delta_ms;
132 }
133 last_acquired_interval_ms = delta_ms;
134 total_acquired_interval_ms += delta_ms;
135 }
136
137 template <typename OutputT>
Dumpbluetooth::os::WakelockManager::Stats138 void Dump(OutputT&& out, bool is_native) {
139 const uint64_t just_now_ms = now_ms();
140
141 // Compute the last acquired interval if the wakelock is still acquired
142 uint64_t delta_ms = 0;
143 uint64_t last_interval_ms = last_acquired_interval_ms;
144 uint64_t min_interval_ms = min_acquired_interval_ms;
145 uint64_t max_interval_ms = max_acquired_interval_ms;
146 uint64_t avg_interval_ms = 0;
147
148 if (is_acquired) {
149 delta_ms = just_now_ms - last_acquired_timestamp_ms;
150 if (delta_ms > max_interval_ms) {
151 max_interval_ms = delta_ms;
152 }
153 if (delta_ms < min_interval_ms) {
154 min_interval_ms = delta_ms;
155 }
156 last_interval_ms = delta_ms;
157 }
158
159 uint64_t total_interval_ms = total_acquired_interval_ms + delta_ms;
160
161 if (acquired_count > 0) {
162 avg_interval_ms = total_interval_ms / acquired_count;
163 }
164
165 std::format_to(out, "\nWakelock Dumpsys:\n");
166 std::format_to(out,
167 " is_acquired: {}\n"
168 " is_native: {}\n"
169 " acquired_count: {}\n"
170 " released_count: {}\n"
171 " acquired_error_count: {}\n"
172 " released_error_count: {}\n"
173 " last_acquired_error_code: {}\n"
174 " last_released_error_code: {}\n"
175 " last_acquired_timestamp_ms: {}\n"
176 " last_released_timestamp_ms: {}\n"
177 " last_interval_ms: {}\n"
178 " max_interval_ms: {}\n"
179 " min_interval_ms: {}\n"
180 " avg_interval_ms: {}\n"
181 " total_interval_ms: {}\n"
182 " total_time_since_reeset_ms: {}\n",
183 is_acquired, is_native, acquired_count, released_count, acquired_errors,
184 released_errors, last_acquired_error, last_released_error, last_interval_ms,
185 last_released_timestamp_ms, last_acquired_interval_ms, max_interval_ms,
186 min_interval_ms, avg_interval_ms, total_interval_ms,
187 just_now_ms - last_reset_timestamp_ms);
188 }
189 };
190
SetOsCallouts(OsCallouts * callouts,Handler * handler)191 void WakelockManager::SetOsCallouts(OsCallouts* callouts, Handler* handler) {
192 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
193 if (initialized_) {
194 log::warn("Setting OS callouts after initialization can lead to wakelock leak!");
195 }
196 os_callouts_ = callouts;
197 os_callouts_handler_ = handler;
198 is_native_ = (os_callouts_ == nullptr);
199 if (is_native_) {
200 log::assert_that(os_callouts_handler_ != nullptr,
201 "handler must not be null when callout is not null");
202 }
203 log::info("set to {}", is_native_ ? "native" : "non-native");
204 }
205
Acquire()206 bool WakelockManager::Acquire() {
207 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
208 if (!initialized_) {
209 if (is_native_) {
210 WakelockNative::Get().Initialize();
211 }
212 initialized_ = true;
213 }
214
215 StatusCode status;
216 if (is_native_) {
217 status = WakelockNative::Get().Acquire(kBtWakelockId);
218 } else {
219 os_callouts_handler_->CallOn(os_callouts_, &OsCallouts::AcquireCallout, kBtWakelockId);
220 status = StatusCode::SUCCESS;
221 }
222
223 pstats_->UpdateAcquiredStats(status);
224
225 if (status != StatusCode::SUCCESS) {
226 log::error("unable to acquire wake lock, error code: {}", status);
227 }
228
229 return status == StatusCode ::SUCCESS;
230 }
231
Release()232 bool WakelockManager::Release() {
233 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
234 if (!initialized_) {
235 if (is_native_) {
236 WakelockNative::Get().Initialize();
237 }
238 initialized_ = true;
239 }
240
241 StatusCode status;
242 if (is_native_) {
243 status = WakelockNative::Get().Release(kBtWakelockId);
244 } else {
245 os_callouts_handler_->CallOn(os_callouts_, &OsCallouts::ReleaseCallout, kBtWakelockId);
246 status = StatusCode ::SUCCESS;
247 }
248
249 pstats_->UpdateReleasedStats(status);
250
251 if (status != StatusCode::SUCCESS) {
252 log::error("unable to release wake lock, error code: {}", status);
253 }
254
255 return status == StatusCode ::SUCCESS;
256 }
257
CleanUp()258 void WakelockManager::CleanUp() {
259 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
260 if (!initialized_) {
261 log::error("Already uninitialized");
262 return;
263 }
264 if (pstats_->is_acquired) {
265 log::error("Releasing wake lock as part of cleanup");
266 Release();
267 }
268 if (is_native_) {
269 WakelockNative::Get().CleanUp();
270 }
271 pstats_->Reset();
272 initialized_ = false;
273 }
274
Dump(int fd) const275 void WakelockManager::Dump(int fd) const {
276 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
277 std::string out;
278 pstats_->Dump(std::back_inserter(out), is_native_);
279 dprintf(fd, "%s", out.c_str());
280 }
281
WakelockManager()282 WakelockManager::WakelockManager() : pstats_(std::make_unique<Stats>()) {}
283
284 WakelockManager::~WakelockManager() = default;
285
286 } // namespace os
287 } // namespace bluetooth
288