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