Home | History | Annotate | Download | only in src
      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