Merge changes Ic4fcbb22,I1be8a18d
* changes:
Bluetooth: Use AsyncFdWatcher for power management
Bluetooth: AsyncFdWatcher: Refactor timeout lock
diff --git a/bluetooth/1.0/default/async_fd_watcher.cc b/bluetooth/1.0/default/async_fd_watcher.cc
index 9cd86f1..161a74a 100644
--- a/bluetooth/1.0/default/async_fd_watcher.cc
+++ b/bluetooth/1.0/default/async_fd_watcher.cc
@@ -140,9 +140,15 @@
// Timeout.
if (retval == 0) {
- std::unique_lock<std::mutex> guard(timeout_mutex_);
- if (timeout_ms_ > std::chrono::milliseconds(0) && timeout_cb_)
- timeout_cb_();
+ // Allow the timeout callback to modify the timeout.
+ TimeoutCallback saved_cb;
+ {
+ std::unique_lock<std::mutex> guard(timeout_mutex_);
+ if (timeout_ms_ > std::chrono::milliseconds(0))
+ saved_cb = timeout_cb_;
+ }
+ if (saved_cb != nullptr)
+ saved_cb();
continue;
}
diff --git a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
index c21acb8..49ea44a 100644
--- a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
+++ b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
@@ -56,8 +56,7 @@
int reuse_flag = 1;
EXPECT_FALSE(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag,
sizeof(reuse_flag)) < 0);
- EXPECT_FALSE(bind(fd, (sockaddr*)&serv_addr, sizeof(serv_addr)) <
- 0);
+ EXPECT_FALSE(bind(fd, (sockaddr*)&serv_addr, sizeof(serv_addr)) < 0);
ALOGD("%s before listen", __func__);
listen(fd, 1);
@@ -81,11 +80,12 @@
int n = TEMP_FAILURE_RETRY(read(fd, server_buffer_, kBufferSize - 1));
EXPECT_FALSE(n < 0);
- if (n == 0) // got EOF
+ if (n == 0) { // got EOF
ALOGD("%s: EOF", __func__);
- else
+ } else {
ALOGD("%s: Got something", __func__);
n = write(fd, "1", 1);
+ }
}
void SetUp() override {
@@ -101,7 +101,10 @@
int connection_fd = AcceptConnection(fd);
ALOGD("%s: Conn_watcher fd = %d", __func__, fd);
- conn_watcher_.ConfigureTimeout(std::chrono::seconds(0), [this]() { bool connection_timeout_cleared = false; ASSERT_TRUE(connection_timeout_cleared); });
+ conn_watcher_.ConfigureTimeout(std::chrono::seconds(0), [this]() {
+ bool connection_timeout_cleared = false;
+ ASSERT_TRUE(connection_timeout_cleared);
+ });
ALOGD("%s: 3", __func__);
async_fd_watcher_.WatchFdForNonBlockingReads(
@@ -110,7 +113,10 @@
// Time out if it takes longer than a second.
SetTimeout(std::chrono::seconds(1));
});
- conn_watcher_.ConfigureTimeout(std::chrono::seconds(1), [this]() { bool connection_timeout = true; ASSERT_FALSE(connection_timeout); });
+ conn_watcher_.ConfigureTimeout(std::chrono::seconds(1), [this]() {
+ bool connection_timeout = true;
+ ASSERT_FALSE(connection_timeout);
+ });
}
void CleanUpServer() {
@@ -135,7 +141,7 @@
}
bool TimedOut() {
- ALOGD("%s %d", __func__, timed_out_? 1 : 0);
+ ALOGD("%s %d", __func__, timed_out_ ? 1 : 0);
return timed_out_;
}
@@ -198,8 +204,8 @@
// Fail if the client doesn't connect within 1 second.
conn_watcher.ConfigureTimeout(std::chrono::seconds(1), [this]() {
- bool connection_timeout = true;
- ASSERT_FALSE(connection_timeout);
+ bool connection_timeout = true;
+ ASSERT_FALSE(connection_timeout);
});
ConnectClient();
@@ -220,7 +226,8 @@
});
// Set the timeout flag after 100ms.
- conn_watcher.ConfigureTimeout(std::chrono::milliseconds(100), [this, timeout_ptr]() { *timeout_ptr = true; });
+ conn_watcher.ConfigureTimeout(std::chrono::milliseconds(100),
+ [this, timeout_ptr]() { *timeout_ptr = true; });
EXPECT_FALSE(timed_out);
sleep(1);
EXPECT_TRUE(timed_out);
@@ -228,6 +235,38 @@
close(socket_fd);
}
+// Modify the timeout in a timeout callback.
+TEST_F(AsyncFdWatcherSocketTest, TimedOutSchedulesTimeout) {
+ int socket_fd = StartServer();
+ bool timed_out = false;
+ bool timed_out2 = false;
+
+ AsyncFdWatcher conn_watcher;
+ conn_watcher.WatchFdForNonBlockingReads(socket_fd, [this](int fd) {
+ int connection_fd = AcceptConnection(fd);
+ close(connection_fd);
+ });
+
+ // Set a timeout flag in each callback.
+ conn_watcher.ConfigureTimeout(
+ std::chrono::milliseconds(500),
+ [this, &conn_watcher, &timed_out, &timed_out2]() {
+ timed_out = true;
+ conn_watcher.ConfigureTimeout(std::chrono::seconds(1),
+ [&timed_out2]() { timed_out2 = true; });
+ });
+ EXPECT_FALSE(timed_out);
+ EXPECT_FALSE(timed_out2);
+ sleep(1);
+ EXPECT_TRUE(timed_out);
+ EXPECT_FALSE(timed_out2);
+ sleep(1);
+ EXPECT_TRUE(timed_out);
+ EXPECT_TRUE(timed_out2);
+ conn_watcher.StopWatchingFileDescriptor();
+ close(socket_fd);
+}
+
// Use two AsyncFdWatchers to set up a server socket.
TEST_F(AsyncFdWatcherSocketTest, ClientServer) {
ConfigureServer();
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index 278b66c..f228982 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -44,6 +44,11 @@
uint16_t opcode;
} internal_command;
+// True when LPM is not enabled yet or wake is not asserted.
+bool lpm_wake_deasserted;
+uint32_t lpm_timeout_ms;
+bool recent_activity_flag;
+
VendorInterface* g_vendor_interface = nullptr;
const size_t preamble_size_for_type[] = {
@@ -271,6 +276,9 @@
fd_watcher_.WatchFdForNonBlockingReads(uart_fd_,
[this](int fd) { OnDataReady(fd); });
+ // Initially, the power management is off.
+ lpm_wake_deasserted = false;
+
// Start configuring the firmware
firmware_startup_timer_ = new FirmwareStartupTimer();
lib_interface_->op(BT_VND_OP_FW_CFG, nullptr);
@@ -302,6 +310,19 @@
size_t VendorInterface::Send(uint8_t type, const uint8_t* data, size_t length) {
if (uart_fd_ == INVALID_FD) return 0;
+ recent_activity_flag = true;
+
+ if (lpm_wake_deasserted == true) {
+ // Restart the timer.
+ fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+ [this]() { OnTimeout(); });
+ // Assert wake.
+ lpm_wake_deasserted = false;
+ bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
+ lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
+ ALOGV("%s: Sent wake before (%02x)", __func__, data[0] | (data[1] << 8));
+ }
+
int rv = write_safely(uart_fd_, &type, sizeof(type));
if (rv == sizeof(type))
rv = write_safely(uart_fd_, data, length);
@@ -321,6 +342,32 @@
initialize_complete_cb_(result == 0);
initialize_complete_cb_ = nullptr;
}
+
+ lib_interface_->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &lpm_timeout_ms);
+ ALOGI("%s: lpm_timeout_ms %d", __func__, lpm_timeout_ms);
+
+ bt_vendor_lpm_mode_t mode = BT_VND_LPM_ENABLE;
+ lib_interface_->op(BT_VND_OP_LPM_SET_MODE, &mode);
+
+ ALOGD("%s Calling StartLowPowerWatchdog()", __func__);
+ fd_watcher_.ConfigureTimeout(std::chrono::milliseconds(lpm_timeout_ms),
+ [this]() { OnTimeout(); });
+
+ bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_ASSERT;
+ lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
+}
+
+void VendorInterface::OnTimeout() {
+ ALOGV("%s", __func__);
+ if (recent_activity_flag == false) {
+ lpm_wake_deasserted = true;
+ bt_vendor_lpm_wake_state_t wakeState = BT_VND_LPM_WAKE_DEASSERT;
+ lib_interface_->op(BT_VND_OP_LPM_WAKE_SET_STATE, &wakeState);
+ fd_watcher_.ConfigureTimeout(std::chrono::seconds(0), []() {
+ ALOGE("Zero timeout! Should never happen.");
+ });
+ }
+ recent_activity_flag = false;
}
void VendorInterface::OnDataReady(int fd) {
diff --git a/bluetooth/1.0/default/vendor_interface.h b/bluetooth/1.0/default/vendor_interface.h
index 79611cd..ce5769c 100644
--- a/bluetooth/1.0/default/vendor_interface.h
+++ b/bluetooth/1.0/default/vendor_interface.h
@@ -53,6 +53,8 @@
PacketReadCallback packet_read_cb);
void Close();
+ void OnTimeout();
+
void OnDataReady(int fd);
void *lib_handle_;