• 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 <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