// 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);
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <limits.h>
#include <malloc.h>
#include <pthread.h>
#include <signal.h>
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;
}
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;
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);
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));
}
}
*
******************************************************************************/
-#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"
current_harness = this;
TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 100;
- lock_count = 0;
struct sigevent sigevent;
memset(&sigevent, 0, sizeof(sigevent));
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);
-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;
+}
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();
};
#pragma once
+#include <gtest/gtest.h>
+
class AllocationTestHarness : public ::testing::Test {
protected:
virtual void SetUp();
msleep(10 + EPSILON_MS);
EXPECT_EQ(cb_counter, 0);
- EXPECT_EQ(lock_count, 0);
+ EXPECT_FALSE(WakeLockHeld());;
alarm_free(alarm);
}
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);
}
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);
}
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]);
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]);
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]);