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 namespace bluetooth {
31 namespace os {
32
33 using internal::WakelockNative;
34 using StatusCode = WakelockNative::StatusCode;
35
now_ms()36 static uint64_t now_ms() {
37 struct timespec ts = {};
38 if (clock_gettime(CLOCK_BOOTTIME, &ts) == -1) {
39 log::error("unable to get current time: {}", strerror(errno));
40 return 0;
41 }
42 return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
43 }
44
45 const std::string WakelockManager::kBtWakelockId = "bluetooth_gd_timer";
46
47 // Wakelock statistics for the "bluetooth_timer"
48 struct WakelockManager::Stats {
49 bool is_acquired = false;
50 size_t acquired_count = 0;
51 size_t released_count = 0;
52 size_t acquired_errors = 0;
53 size_t released_errors = 0;
54 uint64_t min_acquired_interval_ms = 0;
55 uint64_t max_acquired_interval_ms = 0;
56 uint64_t last_acquired_interval_ms = 0;
57 uint64_t total_acquired_interval_ms = 0;
58 uint64_t last_acquired_timestamp_ms = 0;
59 uint64_t last_released_timestamp_ms = 0;
60 uint64_t last_reset_timestamp_ms = now_ms();
61 StatusCode last_acquired_error = StatusCode::SUCCESS;
62 StatusCode last_released_error = StatusCode::SUCCESS;
63
Resetbluetooth::os::WakelockManager::Stats64 void Reset() {
65 is_acquired = false;
66 acquired_count = 0;
67 released_count = 0;
68 acquired_errors = 0;
69 released_errors = 0;
70 min_acquired_interval_ms = 0;
71 max_acquired_interval_ms = 0;
72 last_acquired_interval_ms = 0;
73 total_acquired_interval_ms = 0;
74 last_acquired_timestamp_ms = 0;
75 last_released_timestamp_ms = 0;
76 last_reset_timestamp_ms = now_ms();
77 last_acquired_error = StatusCode::SUCCESS;
78 last_released_error = StatusCode::SUCCESS;
79 }
80
81 // Update the Bluetooth acquire wakelock statistics.
82 //
83 // This function should be called every time when the wakelock is acquired.
84 // |acquired_status| is the status code that was return when the wakelock was
85 // acquired.
UpdateAcquiredStatsbluetooth::os::WakelockManager::Stats86 void UpdateAcquiredStats(StatusCode acquired_status) {
87 const uint64_t just_now_ms = now_ms();
88 if (acquired_status != StatusCode::SUCCESS) {
89 acquired_errors++;
90 last_acquired_error = acquired_status;
91 }
92
93 if (is_acquired) {
94 return;
95 }
96
97 is_acquired = true;
98 acquired_count++;
99 last_acquired_timestamp_ms = just_now_ms;
100 }
101
102 // Update the Bluetooth release wakelock statistics.
103 //
104 // This function should be called every time when the wakelock is released.
105 // |released_status| is the status code that was return when the wakelock was
106 // released.
UpdateReleasedStatsbluetooth::os::WakelockManager::Stats107 void UpdateReleasedStats(StatusCode released_status) {
108 const uint64_t just_now_ms = now_ms();
109 if (released_status != StatusCode::SUCCESS) {
110 released_errors++;
111 last_released_error = released_status;
112 }
113
114 if (!is_acquired) {
115 return;
116 }
117
118 is_acquired = false;
119 released_count++;
120 last_released_timestamp_ms = just_now_ms;
121
122 // Compute the acquired interval and update the statistics
123 uint64_t delta_ms = just_now_ms - last_acquired_timestamp_ms;
124 if (delta_ms < min_acquired_interval_ms || released_count == 1) {
125 min_acquired_interval_ms = delta_ms;
126 }
127 if (delta_ms > max_acquired_interval_ms) {
128 max_acquired_interval_ms = delta_ms;
129 }
130 last_acquired_interval_ms = delta_ms;
131 total_acquired_interval_ms += delta_ms;
132 }
133
134 template <typename OutputT>
Dumpbluetooth::os::WakelockManager::Stats135 void Dump(OutputT&& out, bool is_native) {
136 const uint64_t just_now_ms = now_ms();
137
138 // Compute the last acquired interval if the wakelock is still acquired
139 uint64_t delta_ms = 0;
140 uint64_t last_interval_ms = last_acquired_interval_ms;
141 uint64_t min_interval_ms = min_acquired_interval_ms;
142 uint64_t max_interval_ms = max_acquired_interval_ms;
143 uint64_t avg_interval_ms = 0;
144
145 if (is_acquired) {
146 delta_ms = just_now_ms - last_acquired_timestamp_ms;
147 if (delta_ms > max_interval_ms) {
148 max_interval_ms = delta_ms;
149 }
150 if (delta_ms < min_interval_ms) {
151 min_interval_ms = delta_ms;
152 }
153 last_interval_ms = delta_ms;
154 }
155
156 uint64_t total_interval_ms = total_acquired_interval_ms + delta_ms;
157
158 if (acquired_count > 0) {
159 avg_interval_ms = total_interval_ms / acquired_count;
160 }
161
162 std::format_to(out, "\nWakelock Dumpsys:\n");
163 std::format_to(out,
164 " is_acquired: {}\n"
165 " is_native: {}\n"
166 " acquired_count: {}\n"
167 " released_count: {}\n"
168 " acquired_error_count: {}\n"
169 " released_error_count: {}\n"
170 " last_acquired_error_code: {}\n"
171 " last_released_error_code: {}\n"
172 " last_acquired_timestamp_ms: {}\n"
173 " last_released_timestamp_ms: {}\n"
174 " last_interval_ms: {}\n"
175 " max_interval_ms: {}\n"
176 " min_interval_ms: {}\n"
177 " avg_interval_ms: {}\n"
178 " total_interval_ms: {}\n"
179 " total_time_since_reeset_ms: {}\n",
180 is_acquired, is_native, acquired_count, released_count, acquired_errors,
181 released_errors, last_acquired_error, last_released_error, last_interval_ms,
182 last_released_timestamp_ms, last_acquired_interval_ms, max_interval_ms,
183 min_interval_ms, avg_interval_ms, total_interval_ms,
184 just_now_ms - last_reset_timestamp_ms);
185 }
186 };
187
SetOsCallouts(OsCallouts * callouts,Handler * handler)188 void WakelockManager::SetOsCallouts(OsCallouts* callouts, Handler* handler) {
189 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
190 if (initialized_) {
191 log::warn("Setting OS callouts after initialization can lead to wakelock leak!");
192 }
193 os_callouts_ = callouts;
194 os_callouts_handler_ = handler;
195 is_native_ = (os_callouts_ == nullptr);
196 if (is_native_) {
197 log::assert_that(os_callouts_handler_ != nullptr,
198 "handler must not be null when callout is not null");
199 }
200 log::info("set to {}", is_native_ ? "native" : "non-native");
201 }
202
Acquire()203 bool WakelockManager::Acquire() {
204 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
205 if (!initialized_) {
206 if (is_native_) {
207 WakelockNative::Get().Initialize();
208 }
209 initialized_ = true;
210 }
211
212 StatusCode status;
213 if (is_native_) {
214 status = WakelockNative::Get().Acquire(kBtWakelockId);
215 } else {
216 os_callouts_handler_->CallOn(os_callouts_, &OsCallouts::AcquireCallout, kBtWakelockId);
217 status = StatusCode::SUCCESS;
218 }
219
220 pstats_->UpdateAcquiredStats(status);
221
222 if (status != StatusCode::SUCCESS) {
223 log::error("unable to acquire wake lock, error code: {}", status);
224 }
225
226 return status == StatusCode ::SUCCESS;
227 }
228
Release()229 bool WakelockManager::Release() {
230 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
231 if (!initialized_) {
232 if (is_native_) {
233 WakelockNative::Get().Initialize();
234 }
235 initialized_ = true;
236 }
237
238 StatusCode status;
239 if (is_native_) {
240 status = WakelockNative::Get().Release(kBtWakelockId);
241 } else {
242 os_callouts_handler_->CallOn(os_callouts_, &OsCallouts::ReleaseCallout, kBtWakelockId);
243 status = StatusCode ::SUCCESS;
244 }
245
246 pstats_->UpdateReleasedStats(status);
247
248 if (status != StatusCode::SUCCESS) {
249 log::error("unable to release wake lock, error code: {}", status);
250 }
251
252 return status == StatusCode ::SUCCESS;
253 }
254
CleanUp()255 void WakelockManager::CleanUp() {
256 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
257 if (!initialized_) {
258 log::error("Already uninitialized");
259 return;
260 }
261 if (pstats_->is_acquired) {
262 log::error("Releasing wake lock as part of cleanup");
263 Release();
264 }
265 if (is_native_) {
266 WakelockNative::Get().CleanUp();
267 }
268 pstats_->Reset();
269 initialized_ = false;
270 }
271
Dump(int fd) const272 void WakelockManager::Dump(int fd) const {
273 std::lock_guard<std::recursive_mutex> lock_guard(mutex_);
274 std::string out;
275 pstats_->Dump(std::back_inserter(out), is_native_);
276 dprintf(fd, "%s", out.c_str());
277 }
278
WakelockManager()279 WakelockManager::WakelockManager() : pstats_(std::make_unique<Stats>()) {}
280
281 WakelockManager::~WakelockManager() = default;
282
283 } // namespace os
284 } // namespace bluetooth
285