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