From 1b2bd2c8b5b7be80cb4ce0ecf4e021ad16e4a540 Mon Sep 17 00:00:00 2001 From: Marie Janssen Date: Mon, 16 Nov 2015 10:35:17 -0800 Subject: [PATCH] tests: don't use bt_os_callouts for wakelocks Introduces alarm_set_wake_lock_paths so wake lock paths can be changed for testing, and adds AlarmTestHarness::WakeLockHeld to test whether a wake lock is currently held. Bug: 25387683 Change-Id: I9a41ae8266e252a3d436f8d41ea3f9e7ecb45cdc --- osi/include/alarm.h | 7 +++ osi/src/alarm.c | 50 ++++++++++++++++++--- osi/test/AlarmTestHarness.cpp | 95 +++++++++++++++++++++++++++------------- osi/test/AlarmTestHarness.h | 7 ++- osi/test/AllocationTestHarness.h | 2 + osi/test/alarm_test.cpp | 28 ++++++------ 6 files changed, 136 insertions(+), 53 deletions(-) diff --git a/osi/include/alarm.h b/osi/include/alarm.h index 9307aacc6..4b3e3958a 100644 --- a/osi/include/alarm.h +++ b/osi/include/alarm.h @@ -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); diff --git a/osi/src/alarm.c b/osi/src/alarm.c index 3e7115f3f..9308ad211 100644 --- a/osi/src/alarm.c +++ b/osi/src/alarm.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -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; @@ -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; @@ -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); @@ -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)); } } diff --git a/osi/test/AlarmTestHarness.cpp b/osi/test/AlarmTestHarness.cpp index 1f0cdb525..39407ddc4 100644 --- a/osi/test/AlarmTestHarness.cpp +++ b/osi/test/AlarmTestHarness.cpp @@ -16,11 +16,13 @@ * ******************************************************************************/ -#include -#include +#include "AlarmTestHarness.h" + +#include +#include #include -#include "AlarmTestHarness.h" +#include extern "C" { #include "osi/include/alarm.h" @@ -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)); @@ -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(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); -static bt_os_callouts_t stub = { - sizeof(bt_os_callouts_t), - set_wake_alarm, - acquire_wake_lock, - release_wake_lock, -}; + struct stat lock_stat, unlock_stat; + fstat(lock_fd, &lock_stat); + fstat(unlock_fd, &unlock_stat); -bt_os_callouts_t *bt_os_callouts = &stub; + assert(lock_stat.st_size >= unlock_stat.st_size); + 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; +} diff --git a/osi/test/AlarmTestHarness.h b/osi/test/AlarmTestHarness.h index d4146bbcc..dbd09b0d1 100644 --- a/osi/test/AlarmTestHarness.h +++ b/osi/test/AlarmTestHarness.h @@ -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(); }; diff --git a/osi/test/AllocationTestHarness.h b/osi/test/AllocationTestHarness.h index b90693645..65fc0b00a 100644 --- a/osi/test/AllocationTestHarness.h +++ b/osi/test/AllocationTestHarness.h @@ -18,6 +18,8 @@ #pragma once +#include + class AllocationTestHarness : public ::testing::Test { protected: virtual void SetUp(); diff --git a/osi/test/alarm_test.cpp b/osi/test/alarm_test.cpp index 32e1103e5..1b4895cf3 100644 --- a/osi/test/alarm_test.cpp +++ b/osi/test/alarm_test.cpp @@ -79,7 +79,7 @@ TEST_F(AlarmTest, test_cancel) { msleep(10 + EPSILON_MS); EXPECT_EQ(cb_counter, 0); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld());; alarm_free(alarm); } @@ -97,12 +97,12 @@ TEST_F(AlarmTest, test_set_short) { alarm_set(alarm, 10, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_EQ(lock_count, 1); + EXPECT_TRUE(WakeLockHeld()); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); alarm_free(alarm); } @@ -112,12 +112,12 @@ TEST_F(AlarmTest, test_set_long) { alarm_set(alarm, TIMER_INTERVAL_FOR_WAKELOCK_IN_MS, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); alarm_free(alarm); } @@ -132,17 +132,17 @@ TEST_F(AlarmTest, test_set_short_short) { alarm_set(alarm[1], 20, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_EQ(lock_count, 1); + EXPECT_TRUE(WakeLockHeld()); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_EQ(lock_count, 1); + EXPECT_TRUE(WakeLockHeld()); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 2); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); alarm_free(alarm[0]); alarm_free(alarm[1]); @@ -158,17 +158,17 @@ TEST_F(AlarmTest, test_set_short_long) { alarm_set(alarm[1], 10 + TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_EQ(lock_count, 1); + EXPECT_TRUE(WakeLockHeld()); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 2); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); alarm_free(alarm[0]); alarm_free(alarm[1]); @@ -184,17 +184,17 @@ TEST_F(AlarmTest, test_set_long_long) { alarm_set(alarm[1], 2 * TIMER_INTERVAL_FOR_WAKELOCK_IN_MS + EPSILON_MS, cb, NULL); EXPECT_EQ(cb_counter, 0); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 1); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); semaphore_wait(semaphore); EXPECT_EQ(cb_counter, 2); - EXPECT_EQ(lock_count, 0); + EXPECT_FALSE(WakeLockHeld()); alarm_free(alarm[0]); alarm_free(alarm[1]); -- 2.11.0