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