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 "osi/include/alarm.h" 38 #include "osi/include/allocator.h" 39 #include "osi/include/log.h" 40 #include "osi/include/metrics.h" 41 #include "osi/include/osi.h" 42 #include "osi/include/thread.h" 43 #include "osi/include/wakelock.h" 44 45 using system_bt_osi::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 period_ms_t min_acquired_interval_ms; 69 period_ms_t max_acquired_interval_ms; 70 period_ms_t last_acquired_interval_ms; 71 period_ms_t total_acquired_interval_ms; 72 period_ms_t last_acquired_timestamp_ms; 73 period_ms_t last_released_timestamp_ms; 74 period_ms_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 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 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 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 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 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 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 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 187 static void wakelock_initialize(void) { 188 reset_wakelock_stats(); 189 190 if (is_native) wakelock_initialize_native(); 191 } 192 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 215 void wakelock_cleanup(void) { 216 wake_lock_path.clear(); 217 wake_unlock_path.clear(); 218 initialized = PTHREAD_ONCE_INIT; 219 } 220 221 void wakelock_set_paths(const char* lock_path, const char* unlock_path) { 222 if (lock_path) wake_lock_path = lock_path; 223 224 if (unlock_path) wake_unlock_path = unlock_path; 225 } 226 227 static period_ms_t now(void) { 228 struct timespec ts; 229 if (clock_gettime(CLOCK_ID, &ts) == -1) { 230 LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__, 231 strerror(errno)); 232 return 0; 233 } 234 235 return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL); 236 } 237 238 // Reset the Bluetooth wakelock statistics. 239 // This function is thread-safe. 240 static void reset_wakelock_stats(void) { 241 std::lock_guard<std::mutex> lock(stats_mutex); 242 243 wakelock_stats.is_acquired = false; 244 wakelock_stats.acquired_count = 0; 245 wakelock_stats.released_count = 0; 246 wakelock_stats.acquired_errors = 0; 247 wakelock_stats.released_errors = 0; 248 wakelock_stats.min_acquired_interval_ms = 0; 249 wakelock_stats.max_acquired_interval_ms = 0; 250 wakelock_stats.last_acquired_interval_ms = 0; 251 wakelock_stats.total_acquired_interval_ms = 0; 252 wakelock_stats.last_acquired_timestamp_ms = 0; 253 wakelock_stats.last_released_timestamp_ms = 0; 254 wakelock_stats.last_reset_timestamp_ms = now(); 255 } 256 257 // 258 // Update the Bluetooth acquire wakelock statistics. 259 // 260 // This function should be called every time when the wakelock is acquired. 261 // |acquired_status| is the status code that was return when the wakelock was 262 // acquired. 263 // This function is thread-safe. 264 // 265 static void update_wakelock_acquired_stats(bt_status_t acquired_status) { 266 const period_ms_t now_ms = now(); 267 268 std::lock_guard<std::mutex> lock(stats_mutex); 269 270 if (acquired_status != BT_STATUS_SUCCESS) { 271 wakelock_stats.acquired_errors++; 272 wakelock_stats.last_acquired_error = acquired_status; 273 } 274 275 if (wakelock_stats.is_acquired) { 276 return; 277 } 278 279 wakelock_stats.is_acquired = true; 280 wakelock_stats.acquired_count++; 281 wakelock_stats.last_acquired_timestamp_ms = now_ms; 282 283 BluetoothMetricsLogger::GetInstance()->LogWakeEvent( 284 system_bt_osi::WAKE_EVENT_ACQUIRED, "", "", now_ms); 285 } 286 287 // 288 // Update the Bluetooth release wakelock statistics. 289 // 290 // This function should be called every time when the wakelock is released. 291 // |released_status| is the status code that was return when the wakelock was 292 // released. 293 // This function is thread-safe. 294 // 295 static void update_wakelock_released_stats(bt_status_t released_status) { 296 const period_ms_t now_ms = now(); 297 298 std::lock_guard<std::mutex> lock(stats_mutex); 299 300 if (released_status != BT_STATUS_SUCCESS) { 301 wakelock_stats.released_errors++; 302 wakelock_stats.last_released_error = released_status; 303 } 304 305 if (!wakelock_stats.is_acquired) { 306 return; 307 } 308 309 wakelock_stats.is_acquired = false; 310 wakelock_stats.released_count++; 311 wakelock_stats.last_released_timestamp_ms = now_ms; 312 313 // Compute the acquired interval and update the statistics 314 period_ms_t delta_ms = now_ms - wakelock_stats.last_acquired_timestamp_ms; 315 if (delta_ms < wakelock_stats.min_acquired_interval_ms || 316 wakelock_stats.released_count == 1) { 317 wakelock_stats.min_acquired_interval_ms = delta_ms; 318 } 319 if (delta_ms > wakelock_stats.max_acquired_interval_ms) { 320 wakelock_stats.max_acquired_interval_ms = delta_ms; 321 } 322 wakelock_stats.last_acquired_interval_ms = delta_ms; 323 wakelock_stats.total_acquired_interval_ms += delta_ms; 324 325 BluetoothMetricsLogger::GetInstance()->LogWakeEvent( 326 system_bt_osi::WAKE_EVENT_RELEASED, "", "", now_ms); 327 } 328 329 void wakelock_debug_dump(int fd) { 330 const period_ms_t now_ms = now(); 331 332 std::lock_guard<std::mutex> lock(stats_mutex); 333 334 // Compute the last acquired interval if the wakelock is still acquired 335 period_ms_t delta_ms = 0; 336 period_ms_t last_interval = wakelock_stats.last_acquired_interval_ms; 337 period_ms_t min_interval = wakelock_stats.min_acquired_interval_ms; 338 period_ms_t max_interval = wakelock_stats.max_acquired_interval_ms; 339 period_ms_t ave_interval = 0; 340 341 if (wakelock_stats.is_acquired) { 342 delta_ms = now_ms - wakelock_stats.last_acquired_timestamp_ms; 343 if (delta_ms > max_interval) max_interval = delta_ms; 344 if (delta_ms < min_interval) min_interval = delta_ms; 345 last_interval = delta_ms; 346 } 347 period_ms_t total_interval = 348 wakelock_stats.total_acquired_interval_ms + delta_ms; 349 350 if (wakelock_stats.acquired_count > 0) 351 ave_interval = total_interval / wakelock_stats.acquired_count; 352 353 dprintf(fd, "\nBluetooth Wakelock Statistics:\n"); 354 dprintf(fd, " Is acquired : %s\n", 355 wakelock_stats.is_acquired ? "true" : "false"); 356 dprintf(fd, " Acquired/released count : %zu / %zu\n", 357 wakelock_stats.acquired_count, wakelock_stats.released_count); 358 dprintf(fd, " Acquired/released error count : %zu / %zu\n", 359 wakelock_stats.acquired_errors, wakelock_stats.released_errors); 360 dprintf(fd, " Last acquire/release error code: %d / %d\n", 361 wakelock_stats.last_acquired_error, 362 wakelock_stats.last_released_error); 363 dprintf(fd, " Last acquired time (ms) : %llu\n", 364 (unsigned long long)last_interval); 365 dprintf(fd, " Acquired time min/max/avg (ms) : %llu / %llu / %llu\n", 366 (unsigned long long)min_interval, (unsigned long long)max_interval, 367 (unsigned long long)ave_interval); 368 dprintf(fd, " Total acquired time (ms) : %llu\n", 369 (unsigned long long)total_interval); 370 dprintf( 371 fd, " Total run time (ms) : %llu\n", 372 (unsigned long long)(now_ms - wakelock_stats.last_reset_timestamp_ms)); 373 } 374