summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bluetooth/1.0/default/async_fd_watcher.cc36
-rw-r--r--bluetooth/1.0/default/async_fd_watcher.h6
-rw-r--r--bluetooth/1.0/default/test/async_fd_watcher_unittest.cc66
-rw-r--r--bluetooth/1.0/default/vendor_interface.cc2
4 files changed, 91 insertions, 19 deletions
diff --git a/bluetooth/1.0/default/async_fd_watcher.cc b/bluetooth/1.0/default/async_fd_watcher.cc
index 287d007a..2f23a699 100644
--- a/bluetooth/1.0/default/async_fd_watcher.cc
+++ b/bluetooth/1.0/default/async_fd_watcher.cc
@@ -19,6 +19,7 @@
19#include <algorithm> 19#include <algorithm>
20#include <atomic> 20#include <atomic>
21#include <condition_variable> 21#include <condition_variable>
22#include <map>
22#include <mutex> 23#include <mutex>
23#include <thread> 24#include <thread>
24#include <vector> 25#include <vector>
@@ -26,6 +27,8 @@
26#include "sys/select.h" 27#include "sys/select.h"
27#include "unistd.h" 28#include "unistd.h"
28 29
30static const int INVALID_FD = -1;
31
29namespace android { 32namespace android {
30namespace hardware { 33namespace hardware {
31namespace bluetooth { 34namespace bluetooth {
@@ -36,8 +39,7 @@ int AsyncFdWatcher::WatchFdForNonBlockingReads(
36 // Add file descriptor and callback 39 // Add file descriptor and callback
37 { 40 {
38 std::unique_lock<std::mutex> guard(internal_mutex_); 41 std::unique_lock<std::mutex> guard(internal_mutex_);
39 read_fd_ = file_descriptor; 42 watched_fds_[file_descriptor] = on_read_fd_ready_callback;
40 cb_ = on_read_fd_ready_callback;
41 } 43 }
42 44
43 // Start the thread if not started yet 45 // Start the thread if not started yet
@@ -58,7 +60,7 @@ int AsyncFdWatcher::ConfigureTimeout(
58 return 0; 60 return 0;
59} 61}
60 62
61void AsyncFdWatcher::StopWatchingFileDescriptor() { stopThread(); } 63void AsyncFdWatcher::StopWatchingFileDescriptors() { stopThread(); }
62 64
63AsyncFdWatcher::~AsyncFdWatcher() {} 65AsyncFdWatcher::~AsyncFdWatcher() {}
64 66
@@ -90,8 +92,7 @@ int AsyncFdWatcher::stopThread() {
90 92
91 { 93 {
92 std::unique_lock<std::mutex> guard(internal_mutex_); 94 std::unique_lock<std::mutex> guard(internal_mutex_);
93 cb_ = nullptr; 95 watched_fds_.clear();
94 read_fd_ = -1;
95 } 96 }
96 97
97 { 98 {
@@ -115,7 +116,11 @@ void AsyncFdWatcher::ThreadRoutine() {
115 fd_set read_fds; 116 fd_set read_fds;
116 FD_ZERO(&read_fds); 117 FD_ZERO(&read_fds);
117 FD_SET(notification_listen_fd_, &read_fds); 118 FD_SET(notification_listen_fd_, &read_fds);
118 FD_SET(read_fd_, &read_fds); 119 int max_read_fd = INVALID_FD;
120 for (auto& it : watched_fds_) {
121 FD_SET(it.first, &read_fds);
122 max_read_fd = std::max(max_read_fd, it.first);
123 }
119 124
120 struct timeval timeout; 125 struct timeval timeout;
121 struct timeval* timeout_ptr = NULL; 126 struct timeval* timeout_ptr = NULL;
@@ -126,7 +131,7 @@ void AsyncFdWatcher::ThreadRoutine() {
126 } 131 }
127 132
128 // Wait until there is data available to read on some FD. 133 // Wait until there is data available to read on some FD.
129 int nfds = std::max(notification_listen_fd_, read_fd_); 134 int nfds = std::max(notification_listen_fd_, max_read_fd);
130 int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr); 135 int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr);
131 136
132 // There was some error. 137 // There was some error.
@@ -153,10 +158,21 @@ void AsyncFdWatcher::ThreadRoutine() {
153 continue; 158 continue;
154 } 159 }
155 160
156 // Invoke the data ready callback if appropriate. 161 // Invoke the data ready callbacks if appropriate.
157 if (FD_ISSET(read_fd_, &read_fds)) { 162 std::vector<decltype(watched_fds_)::value_type> saved_callbacks;
163 {
158 std::unique_lock<std::mutex> guard(internal_mutex_); 164 std::unique_lock<std::mutex> guard(internal_mutex_);
159 if (cb_) cb_(read_fd_); 165 for (auto& it : watched_fds_) {
166 if (FD_ISSET(it.first, &read_fds)) {
167 saved_callbacks.push_back(it);
168 }
169 }
170 }
171
172 for (auto& it : saved_callbacks) {
173 if (it.second) {
174 it.second(it.first);
175 }
160 } 176 }
161 } 177 }
162} 178}
diff --git a/bluetooth/1.0/default/async_fd_watcher.h b/bluetooth/1.0/default/async_fd_watcher.h
index 3f7ff544..358cbc3d 100644
--- a/bluetooth/1.0/default/async_fd_watcher.h
+++ b/bluetooth/1.0/default/async_fd_watcher.h
@@ -16,6 +16,7 @@
16 16
17#pragma once 17#pragma once
18 18
19#include <map>
19#include <mutex> 20#include <mutex>
20#include <thread> 21#include <thread>
21 22
@@ -36,7 +37,7 @@ class AsyncFdWatcher {
36 const ReadCallback& on_read_fd_ready_callback); 37 const ReadCallback& on_read_fd_ready_callback);
37 int ConfigureTimeout(const std::chrono::milliseconds timeout, 38 int ConfigureTimeout(const std::chrono::milliseconds timeout,
38 const TimeoutCallback& on_timeout_callback); 39 const TimeoutCallback& on_timeout_callback);
39 void StopWatchingFileDescriptor(); 40 void StopWatchingFileDescriptors();
40 41
41 private: 42 private:
42 AsyncFdWatcher(const AsyncFdWatcher&) = delete; 43 AsyncFdWatcher(const AsyncFdWatcher&) = delete;
@@ -52,10 +53,9 @@ class AsyncFdWatcher {
52 std::mutex internal_mutex_; 53 std::mutex internal_mutex_;
53 std::mutex timeout_mutex_; 54 std::mutex timeout_mutex_;
54 55
55 int read_fd_; 56 std::map<int, ReadCallback> watched_fds_;
56 int notification_listen_fd_; 57 int notification_listen_fd_;
57 int notification_write_fd_; 58 int notification_write_fd_;
58 ReadCallback cb_;
59 TimeoutCallback timeout_cb_; 59 TimeoutCallback timeout_cb_;
60 std::chrono::milliseconds timeout_ms_; 60 std::chrono::milliseconds timeout_ms_;
61}; 61};
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 a7f5bdab..b0c533c9 100644
--- a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
+++ b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc
@@ -14,6 +14,8 @@
14// limitations under the License. 14// limitations under the License.
15// 15//
16 16
17#define LOG_TAG "async_fd_watcher_unittest"
18
17#include "async_fd_watcher.h" 19#include "async_fd_watcher.h"
18#include <gtest/gtest.h> 20#include <gtest/gtest.h>
19#include <cstdint> 21#include <cstdint>
@@ -122,8 +124,8 @@ class AsyncFdWatcherSocketTest : public ::testing::Test {
122 } 124 }
123 125
124 void CleanUpServer() { 126 void CleanUpServer() {
125 async_fd_watcher_.StopWatchingFileDescriptor(); 127 async_fd_watcher_.StopWatchingFileDescriptors();
126 conn_watcher_.StopWatchingFileDescriptor(); 128 conn_watcher_.StopWatchingFileDescriptors();
127 close(socket_fd_); 129 close(socket_fd_);
128 } 130 }
129 131
@@ -211,7 +213,7 @@ TEST_F(AsyncFdWatcherSocketTest, Connect) {
211 }); 213 });
212 214
213 ConnectClient(); 215 ConnectClient();
214 conn_watcher.StopWatchingFileDescriptor(); 216 conn_watcher.StopWatchingFileDescriptors();
215 close(socket_fd); 217 close(socket_fd);
216} 218}
217 219
@@ -233,7 +235,7 @@ TEST_F(AsyncFdWatcherSocketTest, TimedOutConnect) {
233 EXPECT_FALSE(timed_out); 235 EXPECT_FALSE(timed_out);
234 sleep(1); 236 sleep(1);
235 EXPECT_TRUE(timed_out); 237 EXPECT_TRUE(timed_out);
236 conn_watcher.StopWatchingFileDescriptor(); 238 conn_watcher.StopWatchingFileDescriptors();
237 close(socket_fd); 239 close(socket_fd);
238} 240}
239 241
@@ -265,10 +267,64 @@ TEST_F(AsyncFdWatcherSocketTest, TimedOutSchedulesTimeout) {
265 sleep(1); 267 sleep(1);
266 EXPECT_TRUE(timed_out); 268 EXPECT_TRUE(timed_out);
267 EXPECT_TRUE(timed_out2); 269 EXPECT_TRUE(timed_out2);
268 conn_watcher.StopWatchingFileDescriptor(); 270 conn_watcher.StopWatchingFileDescriptors();
269 close(socket_fd); 271 close(socket_fd);
270} 272}
271 273
274// Use a single AsyncFdWatcher to watch two file descriptors.
275TEST_F(AsyncFdWatcherSocketTest, WatchTwoFileDescriptors) {
276 int sockfd[2];
277 socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
278 bool cb1_called = false;
279 bool* cb1_called_ptr = &cb1_called;
280 bool cb2_called = false;
281 bool* cb2_called_ptr = &cb2_called;
282
283 AsyncFdWatcher watcher;
284 watcher.WatchFdForNonBlockingReads(sockfd[0], [cb1_called_ptr](int fd) {
285 char read_buf[1] = {0};
286 int n = TEMP_FAILURE_RETRY(read(fd, read_buf, sizeof(read_buf)));
287 ASSERT_TRUE(n == sizeof(read_buf));
288 ASSERT_TRUE(read_buf[0] == '1');
289 *cb1_called_ptr = true;
290 });
291
292 watcher.WatchFdForNonBlockingReads(sockfd[1], [cb2_called_ptr](int fd) {
293 char read_buf[1] = {0};
294 int n = TEMP_FAILURE_RETRY(read(fd, read_buf, sizeof(read_buf)));
295 ASSERT_TRUE(n == sizeof(read_buf));
296 ASSERT_TRUE(read_buf[0] == '2');
297 *cb2_called_ptr = true;
298 });
299
300 // Fail if the test doesn't pass within 3 seconds
301 watcher.ConfigureTimeout(std::chrono::seconds(3), [this]() {
302 bool connection_timeout = true;
303 ASSERT_FALSE(connection_timeout);
304 });
305
306 EXPECT_FALSE(cb1_called);
307 EXPECT_FALSE(cb2_called);
308
309 char one_buf[1] = {'1'};
310 TEMP_FAILURE_RETRY(write(sockfd[1], one_buf, sizeof(one_buf)));
311
312 sleep(1);
313
314 EXPECT_TRUE(cb1_called);
315 EXPECT_FALSE(cb2_called);
316
317 char two_buf[1] = {'2'};
318 TEMP_FAILURE_RETRY(write(sockfd[0], two_buf, sizeof(two_buf)));
319
320 sleep(1);
321
322 EXPECT_TRUE(cb1_called);
323 EXPECT_TRUE(cb2_called);
324
325 watcher.StopWatchingFileDescriptors();
326}
327
272// Use two AsyncFdWatchers to set up a server socket. 328// Use two AsyncFdWatchers to set up a server socket.
273TEST_F(AsyncFdWatcherSocketTest, ClientServer) { 329TEST_F(AsyncFdWatcherSocketTest, ClientServer) {
274 ConfigureServer(); 330 ConfigureServer();
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index 38781294..2c55d1ce 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -274,7 +274,7 @@ bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb,
274} 274}
275 275
276void VendorInterface::Close() { 276void VendorInterface::Close() {
277 fd_watcher_.StopWatchingFileDescriptor(); 277 fd_watcher_.StopWatchingFileDescriptors();
278 278
279 if (lib_interface_ != nullptr) { 279 if (lib_interface_ != nullptr) {
280 bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE; 280 bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE;