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 <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