Loading system/osi/include/alarm.h +7 −0 Original line number Diff line number Diff line Loading @@ -59,3 +59,10 @@ period_ms_t alarm_get_remaining_ms(const alarm_t *alarm); // Alarm-related state cleanup void alarm_cleanup(void); // This function should not need to be called normally. // /sys/power/wake_{|un}lock are used by default. // This is not guaranteed to have any effect after an alarm has been // set with alarm_set. // If |lock_path| or |unlock_path| are NULL, that path is not changed. void alarm_set_wake_lock_paths(const char *lock_path, const char *unlock_path); system/osi/src/alarm.c +43 −7 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <limits.h> #include <malloc.h> #include <pthread.h> #include <signal.h> Loading Loading @@ -70,8 +71,10 @@ int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000; static const clockid_t CLOCK_ID = CLOCK_BOOTTIME; static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM; static const char *WAKE_LOCK_ID = "bluetooth_timer"; static const char *WAKE_LOCK_PATH = "/sys/power/wake_lock"; static const char *WAKE_UNLOCK_PATH = "/sys/power/wake_unlock"; static char *DEFAULT_WAKE_LOCK_PATH = "/sys/power/wake_lock"; static char *DEFAULT_WAKE_UNLOCK_PATH = "/sys/power/wake_unlock"; static char *wake_lock_path = NULL; static char *wake_unlock_path = NULL; static ssize_t locked_id_len = -1; static pthread_once_t wake_fds_initialized = PTHREAD_ONCE_INIT; static int wake_lock_fd = INVALID_FD; Loading Loading @@ -214,7 +217,17 @@ void alarm_cancel(alarm_t *alarm) { } void alarm_cleanup(void) { // If lazy_initialize never ran there is nothing to do if (wake_lock_path && wake_lock_path != DEFAULT_WAKE_LOCK_PATH) { osi_free(wake_lock_path); wake_lock_path = NULL; } if (wake_unlock_path && wake_unlock_path != DEFAULT_WAKE_UNLOCK_PATH) { osi_free(wake_unlock_path); wake_unlock_path = NULL; } // If lazy_initialize never ran there is nothing else to do if (!alarms) return; Loading @@ -229,9 +242,26 @@ void alarm_cleanup(void) { list_free(alarms); alarms = NULL; wake_fds_initialized = PTHREAD_ONCE_INIT; pthread_mutex_destroy(&monitor); } void alarm_set_wake_lock_paths(const char *lock_path, const char *unlock_path) { if (lock_path) { if (wake_lock_path && wake_lock_path != DEFAULT_WAKE_LOCK_PATH) osi_free(wake_lock_path); wake_lock_path = osi_strndup(lock_path, PATH_MAX); } if (unlock_path) { if (wake_unlock_path && wake_unlock_path != DEFAULT_WAKE_UNLOCK_PATH) osi_free(wake_unlock_path); wake_unlock_path = osi_strndup(unlock_path, PATH_MAX); } } static bool lazy_initialize(void) { assert(alarms == NULL); Loading Loading @@ -478,16 +508,22 @@ static void callback_dispatch(UNUSED_ATTR void *context) { static void initialize_wake_fds(void) { LOG_DEBUG(LOG_TAG, "%s opening wake locks", __func__); wake_lock_fd = open(WAKE_LOCK_PATH, O_RDWR | O_CLOEXEC); if (!wake_lock_path) wake_lock_path = DEFAULT_WAKE_LOCK_PATH; wake_lock_fd = open(wake_lock_path, O_RDWR | O_CLOEXEC); if (wake_lock_fd == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s can't open wake lock %s: %s", __func__, WAKE_LOCK_PATH, strerror(errno)); __func__, wake_lock_path, strerror(errno)); } wake_unlock_fd = open(WAKE_UNLOCK_PATH, O_RDWR | O_CLOEXEC); if (!wake_unlock_path) wake_unlock_path = DEFAULT_WAKE_UNLOCK_PATH; wake_unlock_fd = open(wake_unlock_path, O_RDWR | O_CLOEXEC); if (wake_unlock_fd == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s can't open wake unlock %s: %s", __func__, WAKE_UNLOCK_PATH, strerror(errno)); __func__, wake_unlock_path, strerror(errno)); } } Loading system/osi/test/AlarmTestHarness.cpp +64 −31 Original line number Diff line number Diff line Loading @@ -16,11 +16,13 @@ * ******************************************************************************/ #include <gtest/gtest.h> #include <hardware/bluetooth.h> #include "AlarmTestHarness.h" #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include "AlarmTestHarness.h" #include <hardware/bluetooth.h> extern "C" { #include "osi/include/alarm.h" Loading @@ -41,7 +43,6 @@ void AlarmTestHarness::SetUp() { current_harness = this; TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 100; lock_count = 0; struct sigevent sigevent; memset(&sigevent, 0, sizeof(sigevent)); Loading @@ -49,44 +50,76 @@ void AlarmTestHarness::SetUp() { sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback; sigevent.sigev_value.sival_ptr = NULL; timer_create(CLOCK_BOOTTIME, &sigevent, &timer); // TODO (jamuraa): maybe use base::CreateNewTempDirectory instead? #if defined(OS_GENERIC) tmp_dir_ = "/tmp/btwlXXXXXX"; #else // !defined(OS_GENERIC) tmp_dir_ = "/data/local/tmp/btwlXXXXXX"; #endif // !defined(OS_GENERIC) char *buffer = const_cast<char *>(tmp_dir_.c_str()); char *dtemp = mkdtemp(buffer); if (!dtemp) { perror("Can't make wake lock test directory: "); assert(false); } lock_path_ = tmp_dir_ + "/wake_lock"; unlock_path_ = tmp_dir_ + "/wake_unlock"; creat(lock_path_.c_str(), S_IRWXU); creat(unlock_path_.c_str(), S_IRWXU); alarm_set_wake_lock_paths(lock_path_.c_str(), unlock_path_.c_str()); } void AlarmTestHarness::TearDown() { alarm_cleanup(); // clean up the temp wake lock directory unlink(lock_path_.c_str()); unlink(unlock_path_.c_str()); rmdir(tmp_dir_.c_str()); timer_delete(timer); AllocationTestHarness::TearDown(); } static bool set_wake_alarm(uint64_t delay_millis, bool, alarm_cb cb, void *data) { saved_callback = cb; saved_data = data; struct itimerspec wakeup_time; memset(&wakeup_time, 0, sizeof(wakeup_time)); wakeup_time.it_value.tv_sec = (delay_millis / 1000); wakeup_time.it_value.tv_nsec = (delay_millis % 1000) * 1000000LL; timer_settime(timer, 0, &wakeup_time, NULL); return true; } bool AlarmTestHarness::WakeLockHeld() { bool held = false; static int acquire_wake_lock(const char *) { if (!current_harness->lock_count) current_harness->lock_count = 1; return BT_STATUS_SUCCESS; } int lock_fd = open(lock_path_.c_str(), O_RDONLY); assert(lock_fd >= 0); static int release_wake_lock(const char *) { if (current_harness->lock_count) current_harness->lock_count = 0; return BT_STATUS_SUCCESS; } int unlock_fd = open(unlock_path_.c_str(), O_RDONLY); assert(unlock_fd >= 0); struct stat lock_stat, unlock_stat; fstat(lock_fd, &lock_stat); fstat(unlock_fd, &unlock_stat); static bt_os_callouts_t stub = { sizeof(bt_os_callouts_t), set_wake_alarm, acquire_wake_lock, release_wake_lock, }; assert(lock_stat.st_size >= unlock_stat.st_size); bt_os_callouts_t *bt_os_callouts = &stub; void *lock_file = mmap(nullptr, lock_stat.st_size, PROT_READ, MAP_PRIVATE, lock_fd, 0); void *unlock_file = mmap(nullptr, unlock_stat.st_size, PROT_READ, MAP_PRIVATE, unlock_fd, 0); if (memcmp(lock_file, unlock_file, unlock_stat.st_size) == 0) { held = lock_stat.st_size > unlock_stat.st_size; } else { // these files should always either be with a lock that has more, // or equal. assert(false); } munmap(lock_file, lock_stat.st_size); munmap(unlock_file, unlock_stat.st_size); close(lock_fd); close(unlock_fd); return held; } system/osi/test/AlarmTestHarness.h +6 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,11 @@ class AlarmTestHarness : public AllocationTestHarness { virtual void SetUp(); virtual void TearDown(); std::string tmp_dir_; std::string lock_path_; std::string unlock_path_; public: int lock_count; // Returns true if a wake lock is held. bool WakeLockHeld(); }; system/osi/test/AllocationTestHarness.h +2 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ #pragma once #include <gtest/gtest.h> class AllocationTestHarness : public ::testing::Test { protected: virtual void SetUp(); Loading Loading
system/osi/include/alarm.h +7 −0 Original line number Diff line number Diff line Loading @@ -59,3 +59,10 @@ period_ms_t alarm_get_remaining_ms(const alarm_t *alarm); // Alarm-related state cleanup void alarm_cleanup(void); // This function should not need to be called normally. // /sys/power/wake_{|un}lock are used by default. // This is not guaranteed to have any effect after an alarm has been // set with alarm_set. // If |lock_path| or |unlock_path| are NULL, that path is not changed. void alarm_set_wake_lock_paths(const char *lock_path, const char *unlock_path);
system/osi/src/alarm.c +43 −7 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <errno.h> #include <fcntl.h> #include <inttypes.h> #include <limits.h> #include <malloc.h> #include <pthread.h> #include <signal.h> Loading Loading @@ -70,8 +71,10 @@ int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000; static const clockid_t CLOCK_ID = CLOCK_BOOTTIME; static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM; static const char *WAKE_LOCK_ID = "bluetooth_timer"; static const char *WAKE_LOCK_PATH = "/sys/power/wake_lock"; static const char *WAKE_UNLOCK_PATH = "/sys/power/wake_unlock"; static char *DEFAULT_WAKE_LOCK_PATH = "/sys/power/wake_lock"; static char *DEFAULT_WAKE_UNLOCK_PATH = "/sys/power/wake_unlock"; static char *wake_lock_path = NULL; static char *wake_unlock_path = NULL; static ssize_t locked_id_len = -1; static pthread_once_t wake_fds_initialized = PTHREAD_ONCE_INIT; static int wake_lock_fd = INVALID_FD; Loading Loading @@ -214,7 +217,17 @@ void alarm_cancel(alarm_t *alarm) { } void alarm_cleanup(void) { // If lazy_initialize never ran there is nothing to do if (wake_lock_path && wake_lock_path != DEFAULT_WAKE_LOCK_PATH) { osi_free(wake_lock_path); wake_lock_path = NULL; } if (wake_unlock_path && wake_unlock_path != DEFAULT_WAKE_UNLOCK_PATH) { osi_free(wake_unlock_path); wake_unlock_path = NULL; } // If lazy_initialize never ran there is nothing else to do if (!alarms) return; Loading @@ -229,9 +242,26 @@ void alarm_cleanup(void) { list_free(alarms); alarms = NULL; wake_fds_initialized = PTHREAD_ONCE_INIT; pthread_mutex_destroy(&monitor); } void alarm_set_wake_lock_paths(const char *lock_path, const char *unlock_path) { if (lock_path) { if (wake_lock_path && wake_lock_path != DEFAULT_WAKE_LOCK_PATH) osi_free(wake_lock_path); wake_lock_path = osi_strndup(lock_path, PATH_MAX); } if (unlock_path) { if (wake_unlock_path && wake_unlock_path != DEFAULT_WAKE_UNLOCK_PATH) osi_free(wake_unlock_path); wake_unlock_path = osi_strndup(unlock_path, PATH_MAX); } } static bool lazy_initialize(void) { assert(alarms == NULL); Loading Loading @@ -478,16 +508,22 @@ static void callback_dispatch(UNUSED_ATTR void *context) { static void initialize_wake_fds(void) { LOG_DEBUG(LOG_TAG, "%s opening wake locks", __func__); wake_lock_fd = open(WAKE_LOCK_PATH, O_RDWR | O_CLOEXEC); if (!wake_lock_path) wake_lock_path = DEFAULT_WAKE_LOCK_PATH; wake_lock_fd = open(wake_lock_path, O_RDWR | O_CLOEXEC); if (wake_lock_fd == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s can't open wake lock %s: %s", __func__, WAKE_LOCK_PATH, strerror(errno)); __func__, wake_lock_path, strerror(errno)); } wake_unlock_fd = open(WAKE_UNLOCK_PATH, O_RDWR | O_CLOEXEC); if (!wake_unlock_path) wake_unlock_path = DEFAULT_WAKE_UNLOCK_PATH; wake_unlock_fd = open(wake_unlock_path, O_RDWR | O_CLOEXEC); if (wake_unlock_fd == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s can't open wake unlock %s: %s", __func__, WAKE_UNLOCK_PATH, strerror(errno)); __func__, wake_unlock_path, strerror(errno)); } } Loading
system/osi/test/AlarmTestHarness.cpp +64 −31 Original line number Diff line number Diff line Loading @@ -16,11 +16,13 @@ * ******************************************************************************/ #include <gtest/gtest.h> #include <hardware/bluetooth.h> #include "AlarmTestHarness.h" #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include "AlarmTestHarness.h" #include <hardware/bluetooth.h> extern "C" { #include "osi/include/alarm.h" Loading @@ -41,7 +43,6 @@ void AlarmTestHarness::SetUp() { current_harness = this; TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 100; lock_count = 0; struct sigevent sigevent; memset(&sigevent, 0, sizeof(sigevent)); Loading @@ -49,44 +50,76 @@ void AlarmTestHarness::SetUp() { sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback; sigevent.sigev_value.sival_ptr = NULL; timer_create(CLOCK_BOOTTIME, &sigevent, &timer); // TODO (jamuraa): maybe use base::CreateNewTempDirectory instead? #if defined(OS_GENERIC) tmp_dir_ = "/tmp/btwlXXXXXX"; #else // !defined(OS_GENERIC) tmp_dir_ = "/data/local/tmp/btwlXXXXXX"; #endif // !defined(OS_GENERIC) char *buffer = const_cast<char *>(tmp_dir_.c_str()); char *dtemp = mkdtemp(buffer); if (!dtemp) { perror("Can't make wake lock test directory: "); assert(false); } lock_path_ = tmp_dir_ + "/wake_lock"; unlock_path_ = tmp_dir_ + "/wake_unlock"; creat(lock_path_.c_str(), S_IRWXU); creat(unlock_path_.c_str(), S_IRWXU); alarm_set_wake_lock_paths(lock_path_.c_str(), unlock_path_.c_str()); } void AlarmTestHarness::TearDown() { alarm_cleanup(); // clean up the temp wake lock directory unlink(lock_path_.c_str()); unlink(unlock_path_.c_str()); rmdir(tmp_dir_.c_str()); timer_delete(timer); AllocationTestHarness::TearDown(); } static bool set_wake_alarm(uint64_t delay_millis, bool, alarm_cb cb, void *data) { saved_callback = cb; saved_data = data; struct itimerspec wakeup_time; memset(&wakeup_time, 0, sizeof(wakeup_time)); wakeup_time.it_value.tv_sec = (delay_millis / 1000); wakeup_time.it_value.tv_nsec = (delay_millis % 1000) * 1000000LL; timer_settime(timer, 0, &wakeup_time, NULL); return true; } bool AlarmTestHarness::WakeLockHeld() { bool held = false; static int acquire_wake_lock(const char *) { if (!current_harness->lock_count) current_harness->lock_count = 1; return BT_STATUS_SUCCESS; } int lock_fd = open(lock_path_.c_str(), O_RDONLY); assert(lock_fd >= 0); static int release_wake_lock(const char *) { if (current_harness->lock_count) current_harness->lock_count = 0; return BT_STATUS_SUCCESS; } int unlock_fd = open(unlock_path_.c_str(), O_RDONLY); assert(unlock_fd >= 0); struct stat lock_stat, unlock_stat; fstat(lock_fd, &lock_stat); fstat(unlock_fd, &unlock_stat); static bt_os_callouts_t stub = { sizeof(bt_os_callouts_t), set_wake_alarm, acquire_wake_lock, release_wake_lock, }; assert(lock_stat.st_size >= unlock_stat.st_size); bt_os_callouts_t *bt_os_callouts = &stub; void *lock_file = mmap(nullptr, lock_stat.st_size, PROT_READ, MAP_PRIVATE, lock_fd, 0); void *unlock_file = mmap(nullptr, unlock_stat.st_size, PROT_READ, MAP_PRIVATE, unlock_fd, 0); if (memcmp(lock_file, unlock_file, unlock_stat.st_size) == 0) { held = lock_stat.st_size > unlock_stat.st_size; } else { // these files should always either be with a lock that has more, // or equal. assert(false); } munmap(lock_file, lock_stat.st_size); munmap(unlock_file, unlock_stat.st_size); close(lock_fd); close(unlock_fd); return held; }
system/osi/test/AlarmTestHarness.h +6 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,11 @@ class AlarmTestHarness : public AllocationTestHarness { virtual void SetUp(); virtual void TearDown(); std::string tmp_dir_; std::string lock_path_; std::string unlock_path_; public: int lock_count; // Returns true if a wake lock is held. bool WakeLockHeld(); };
system/osi/test/AllocationTestHarness.h +2 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ #pragma once #include <gtest/gtest.h> class AllocationTestHarness : public ::testing::Test { protected: virtual void SetUp(); Loading