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