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