• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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