1 /******************************************************************************
2 *
3 * Copyright 2015 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 "bt_osi_wakelock"
20
21 #include "osi/include/wakelock.h"
22
23 #include <bluetooth/log.h>
24 #include <fcntl.h>
25 #include <hardware/bluetooth.h>
26 #include <pthread.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <time.h>
31 #include <unistd.h>
32
33 #include <mutex>
34 #include <string>
35
36 #include "osi/include/osi.h"
37
38 using namespace bluetooth;
39
40 static bt_os_callouts_t* wakelock_os_callouts = NULL;
41 static bool is_native = true;
42
43 static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
44 static const char* WAKE_LOCK_ID = "bluetooth_timer";
45 static const std::string DEFAULT_WAKE_LOCK_PATH = "/sys/power/wake_lock";
46 static const std::string DEFAULT_WAKE_UNLOCK_PATH = "/sys/power/wake_unlock";
47 static std::string wake_lock_path;
48 static std::string wake_unlock_path;
49 static ssize_t locked_id_len = -1;
50 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
51 static int wake_lock_fd = INVALID_FD;
52 static int wake_unlock_fd = INVALID_FD;
53
54 // Wakelock statistics for the "bluetooth_timer"
55 typedef struct {
56 bool is_acquired;
57 size_t acquired_count;
58 size_t released_count;
59 size_t acquired_errors;
60 size_t released_errors;
61 uint64_t min_acquired_interval_ms;
62 uint64_t max_acquired_interval_ms;
63 uint64_t last_acquired_interval_ms;
64 uint64_t total_acquired_interval_ms;
65 uint64_t last_acquired_timestamp_ms;
66 uint64_t last_released_timestamp_ms;
67 uint64_t last_reset_timestamp_ms;
68 int last_acquired_error;
69 int last_released_error;
70 } wakelock_stats_t;
71
72 static wakelock_stats_t wakelock_stats;
73
74 // This mutex ensures that the functions that update and dump the statistics
75 // are executed serially.
76 static std::mutex stats_mutex;
77
78 static bt_status_t wakelock_acquire_callout(void);
79 static bt_status_t wakelock_acquire_native(void);
80 static bt_status_t wakelock_release_callout(void);
81 static bt_status_t wakelock_release_native(void);
82 static void wakelock_initialize(void);
83 static void wakelock_initialize_native(void);
84 static void reset_wakelock_stats(void);
85 static void update_wakelock_acquired_stats(bt_status_t acquired_status);
86 static void update_wakelock_released_stats(bt_status_t released_status);
87
wakelock_set_os_callouts(bt_os_callouts_t * callouts)88 void wakelock_set_os_callouts(bt_os_callouts_t* callouts) {
89 wakelock_os_callouts = callouts;
90 is_native = (wakelock_os_callouts == NULL);
91 log::info("set to {}", (is_native) ? "native" : "non-native");
92 }
93
wakelock_acquire(void)94 bool wakelock_acquire(void) {
95 pthread_once(&initialized, wakelock_initialize);
96
97 bt_status_t status = BT_STATUS_FAIL;
98
99 if (is_native) {
100 status = wakelock_acquire_native();
101 } else {
102 status = wakelock_acquire_callout();
103 }
104
105 update_wakelock_acquired_stats(status);
106
107 if (status != BT_STATUS_SUCCESS) {
108 log::error("unable to acquire wake lock: {}", status);
109 }
110
111 return status == BT_STATUS_SUCCESS;
112 }
113
wakelock_acquire_callout(void)114 static bt_status_t wakelock_acquire_callout(void) {
115 return static_cast<bt_status_t>(wakelock_os_callouts->acquire_wake_lock(WAKE_LOCK_ID));
116 }
117
wakelock_acquire_native(void)118 static bt_status_t wakelock_acquire_native(void) {
119 if (wake_lock_fd == INVALID_FD) {
120 log::error("lock not acquired, invalid fd");
121 return BT_STATUS_PARM_INVALID;
122 }
123
124 if (wake_unlock_fd == INVALID_FD) {
125 log::error("not acquiring lock: can't release lock");
126 return BT_STATUS_PARM_INVALID;
127 }
128
129 long lock_name_len = strlen(WAKE_LOCK_ID);
130 locked_id_len = write(wake_lock_fd, WAKE_LOCK_ID, lock_name_len);
131 if (locked_id_len == -1) {
132 log::error("wake lock not acquired: {}", strerror(errno));
133 return BT_STATUS_WAKELOCK_ERROR;
134 } else if (locked_id_len < lock_name_len) {
135 // TODO (jamuraa): this is weird. maybe we should release and retry.
136 log::warn("wake lock truncated to {} chars", locked_id_len);
137 }
138 return BT_STATUS_SUCCESS;
139 }
140
wakelock_release(void)141 bool wakelock_release(void) {
142 pthread_once(&initialized, wakelock_initialize);
143
144 bt_status_t status = BT_STATUS_FAIL;
145
146 if (is_native) {
147 status = wakelock_release_native();
148 } else {
149 status = wakelock_release_callout();
150 }
151
152 update_wakelock_released_stats(status);
153
154 return status == BT_STATUS_SUCCESS;
155 }
156
wakelock_release_callout(void)157 static bt_status_t wakelock_release_callout(void) {
158 return static_cast<bt_status_t>(wakelock_os_callouts->release_wake_lock(WAKE_LOCK_ID));
159 }
160
wakelock_release_native(void)161 static bt_status_t wakelock_release_native(void) {
162 if (wake_unlock_fd == INVALID_FD) {
163 log::error("lock not released, invalid fd");
164 return BT_STATUS_PARM_INVALID;
165 }
166
167 ssize_t wrote_name_len = write(wake_unlock_fd, WAKE_LOCK_ID, locked_id_len);
168 if (wrote_name_len == -1) {
169 log::error("can't release wake lock: {}", strerror(errno));
170 } else if (wrote_name_len < locked_id_len) {
171 log::error("lock release only wrote {}, assuming released", wrote_name_len);
172 }
173 return BT_STATUS_SUCCESS;
174 }
175
wakelock_initialize(void)176 static void wakelock_initialize(void) {
177 reset_wakelock_stats();
178
179 if (is_native) {
180 wakelock_initialize_native();
181 }
182 }
183
wakelock_initialize_native(void)184 static void wakelock_initialize_native(void) {
185 log::info("opening wake locks");
186
187 if (wake_lock_path.empty()) {
188 wake_lock_path = DEFAULT_WAKE_LOCK_PATH;
189 }
190
191 wake_lock_fd = open(wake_lock_path.c_str(), O_RDWR | O_CLOEXEC);
192 if (wake_lock_fd == INVALID_FD) {
193 log::error("can't open wake lock {}: {}", wake_lock_path, strerror(errno));
194 }
195
196 if (wake_unlock_path.empty()) {
197 wake_unlock_path = DEFAULT_WAKE_UNLOCK_PATH;
198 }
199
200 wake_unlock_fd = open(wake_unlock_path.c_str(), O_RDWR | O_CLOEXEC);
201 if (wake_unlock_fd == INVALID_FD) {
202 log::error("can't open wake unlock {}: {}", wake_unlock_path, strerror(errno));
203 }
204 }
205
wakelock_cleanup(void)206 void wakelock_cleanup(void) {
207 if (wakelock_stats.is_acquired) {
208 log::error("releasing wake lock as part of cleanup");
209 wakelock_release();
210 }
211 wake_lock_path.clear();
212 wake_unlock_path.clear();
213 initialized = PTHREAD_ONCE_INIT;
214 }
215
wakelock_set_paths(const char * lock_path,const char * unlock_path)216 void wakelock_set_paths(const char* lock_path, const char* unlock_path) {
217 if (lock_path) {
218 wake_lock_path = lock_path;
219 }
220
221 if (unlock_path) {
222 wake_unlock_path = unlock_path;
223 }
224 }
225
now_ms(void)226 static uint64_t now_ms(void) {
227 struct timespec ts;
228 if (clock_gettime(CLOCK_ID, &ts) == -1) {
229 log::error("unable to get current time: {}", strerror(errno));
230 return 0;
231 }
232
233 return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
234 }
235
236 // Reset the Bluetooth wakelock statistics.
237 // This function is thread-safe.
reset_wakelock_stats(void)238 static void reset_wakelock_stats(void) {
239 std::lock_guard<std::mutex> lock(stats_mutex);
240
241 wakelock_stats.is_acquired = false;
242 wakelock_stats.acquired_count = 0;
243 wakelock_stats.released_count = 0;
244 wakelock_stats.acquired_errors = 0;
245 wakelock_stats.released_errors = 0;
246 wakelock_stats.min_acquired_interval_ms = 0;
247 wakelock_stats.max_acquired_interval_ms = 0;
248 wakelock_stats.last_acquired_interval_ms = 0;
249 wakelock_stats.total_acquired_interval_ms = 0;
250 wakelock_stats.last_acquired_timestamp_ms = 0;
251 wakelock_stats.last_released_timestamp_ms = 0;
252 wakelock_stats.last_reset_timestamp_ms = now_ms();
253 }
254
255 //
256 // Update the Bluetooth acquire wakelock statistics.
257 //
258 // This function should be called every time when the wakelock is acquired.
259 // |acquired_status| is the status code that was return when the wakelock was
260 // acquired.
261 // This function is thread-safe.
262 //
update_wakelock_acquired_stats(bt_status_t acquired_status)263 static void update_wakelock_acquired_stats(bt_status_t acquired_status) {
264 const uint64_t just_now_ms = now_ms();
265
266 std::lock_guard<std::mutex> lock(stats_mutex);
267
268 if (acquired_status != BT_STATUS_SUCCESS) {
269 wakelock_stats.acquired_errors++;
270 wakelock_stats.last_acquired_error = acquired_status;
271 }
272
273 if (wakelock_stats.is_acquired) {
274 return;
275 }
276
277 wakelock_stats.is_acquired = true;
278 wakelock_stats.acquired_count++;
279 wakelock_stats.last_acquired_timestamp_ms = just_now_ms;
280 }
281
282 //
283 // Update the Bluetooth release wakelock statistics.
284 //
285 // This function should be called every time when the wakelock is released.
286 // |released_status| is the status code that was return when the wakelock was
287 // released.
288 // This function is thread-safe.
289 //
update_wakelock_released_stats(bt_status_t released_status)290 static void update_wakelock_released_stats(bt_status_t released_status) {
291 const uint64_t just_now_ms = now_ms();
292
293 std::lock_guard<std::mutex> lock(stats_mutex);
294
295 if (released_status != BT_STATUS_SUCCESS) {
296 wakelock_stats.released_errors++;
297 wakelock_stats.last_released_error = released_status;
298 }
299
300 if (!wakelock_stats.is_acquired) {
301 return;
302 }
303
304 wakelock_stats.is_acquired = false;
305 wakelock_stats.released_count++;
306 wakelock_stats.last_released_timestamp_ms = just_now_ms;
307
308 // Compute the acquired interval and update the statistics
309 uint64_t delta_ms = just_now_ms - wakelock_stats.last_acquired_timestamp_ms;
310 if (delta_ms < wakelock_stats.min_acquired_interval_ms || wakelock_stats.released_count == 1) {
311 wakelock_stats.min_acquired_interval_ms = delta_ms;
312 }
313 if (delta_ms > wakelock_stats.max_acquired_interval_ms) {
314 wakelock_stats.max_acquired_interval_ms = delta_ms;
315 }
316 wakelock_stats.last_acquired_interval_ms = delta_ms;
317 wakelock_stats.total_acquired_interval_ms += delta_ms;
318 }
319
wakelock_debug_dump(int fd)320 void wakelock_debug_dump(int fd) {
321 const uint64_t just_now_ms = now_ms();
322
323 std::lock_guard<std::mutex> lock(stats_mutex);
324
325 // Compute the last acquired interval if the wakelock is still acquired
326 uint64_t delta_ms = 0;
327 uint64_t last_interval_ms = wakelock_stats.last_acquired_interval_ms;
328 uint64_t min_interval_ms = wakelock_stats.min_acquired_interval_ms;
329 uint64_t max_interval_ms = wakelock_stats.max_acquired_interval_ms;
330 uint64_t avg_interval_ms = 0;
331
332 if (wakelock_stats.is_acquired) {
333 delta_ms = just_now_ms - wakelock_stats.last_acquired_timestamp_ms;
334 if (delta_ms > max_interval_ms) {
335 max_interval_ms = delta_ms;
336 }
337 if (delta_ms < min_interval_ms) {
338 min_interval_ms = delta_ms;
339 }
340 last_interval_ms = delta_ms;
341 }
342 uint64_t total_interval_ms = wakelock_stats.total_acquired_interval_ms + delta_ms;
343
344 if (wakelock_stats.acquired_count > 0) {
345 avg_interval_ms = total_interval_ms / wakelock_stats.acquired_count;
346 }
347
348 dprintf(fd, "\nBluetooth Wakelock Statistics:\n");
349 dprintf(fd, " Is acquired : %s\n",
350 wakelock_stats.is_acquired ? "true" : "false");
351 dprintf(fd, " Acquired/released count : %zu / %zu\n", wakelock_stats.acquired_count,
352 wakelock_stats.released_count);
353 dprintf(fd, " Acquired/released error count : %zu / %zu\n", wakelock_stats.acquired_errors,
354 wakelock_stats.released_errors);
355 dprintf(fd, " Last acquire/release error code: %d / %d\n", wakelock_stats.last_acquired_error,
356 wakelock_stats.last_released_error);
357 dprintf(fd, " Last acquired time (ms) : %llu\n", (unsigned long long)last_interval_ms);
358 dprintf(fd, " Acquired time min/max/avg (ms) : %llu / %llu / %llu\n",
359 (unsigned long long)min_interval_ms, (unsigned long long)max_interval_ms,
360 (unsigned long long)avg_interval_ms);
361 dprintf(fd, " Total acquired time (ms) : %llu\n", (unsigned long long)total_interval_ms);
362 dprintf(fd, " Total run time (ms) : %llu\n",
363 (unsigned long long)(just_now_ms - wakelock_stats.last_reset_timestamp_ms));
364 }
365