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