blob: ab8d55547f64e2b3571d1e5ad89a3d3c957218dd [file] [log] [blame]
Andre Eisenbach89ba5282016-10-13 15:45:02 -07001//
2// Copyright 2016 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
Philip Cuadra8b3f3152017-04-20 16:02:48 -070017#define LOG_TAG "android.hardware.bluetooth@1.0-impl"
18
Andre Eisenbach89ba5282016-10-13 15:45:02 -070019#include "async_fd_watcher.h"
20
21#include <algorithm>
22#include <atomic>
23#include <condition_variable>
Myles Watsonf3a3cb72017-03-02 09:26:53 -080024#include <map>
Andre Eisenbach89ba5282016-10-13 15:45:02 -070025#include <mutex>
26#include <thread>
Philip Cuadra8b3f3152017-04-20 16:02:48 -070027#include <utils/Log.h>
Andre Eisenbach89ba5282016-10-13 15:45:02 -070028#include <vector>
29#include "fcntl.h"
30#include "sys/select.h"
31#include "unistd.h"
32
Philip Cuadra8b3f3152017-04-20 16:02:48 -070033#include <android/frameworks/schedulerservice/1.0/ISchedulingPolicyService.h>
34
Myles Watsonf3a3cb72017-03-02 09:26:53 -080035static const int INVALID_FD = -1;
36
Philip Cuadra8b3f3152017-04-20 16:02:48 -070037static const int BT_RT_PRIORITY = 1;
38
Andre Eisenbach89ba5282016-10-13 15:45:02 -070039namespace android {
40namespace hardware {
41namespace bluetooth {
Myles Watsonbe6176d2017-02-21 13:27:01 -080042namespace async {
Andre Eisenbach89ba5282016-10-13 15:45:02 -070043
44int AsyncFdWatcher::WatchFdForNonBlockingReads(
45 int file_descriptor, const ReadCallback& on_read_fd_ready_callback) {
46 // Add file descriptor and callback
47 {
48 std::unique_lock<std::mutex> guard(internal_mutex_);
Myles Watsonf3a3cb72017-03-02 09:26:53 -080049 watched_fds_[file_descriptor] = on_read_fd_ready_callback;
Andre Eisenbach89ba5282016-10-13 15:45:02 -070050 }
51
52 // Start the thread if not started yet
Myles Watson5ea487b2017-02-21 16:53:34 -080053 return tryStartThread();
Andre Eisenbach89ba5282016-10-13 15:45:02 -070054}
55
Myles Watson7d42dca2017-01-24 16:51:39 -080056int AsyncFdWatcher::ConfigureTimeout(
57 const std::chrono::milliseconds timeout,
58 const TimeoutCallback& on_timeout_callback) {
59 // Add timeout and callback
60 {
61 std::unique_lock<std::mutex> guard(timeout_mutex_);
62 timeout_cb_ = on_timeout_callback;
63 timeout_ms_ = timeout;
64 }
65
66 notifyThread();
67 return 0;
68}
69
Myles Watsonf3a3cb72017-03-02 09:26:53 -080070void AsyncFdWatcher::StopWatchingFileDescriptors() { stopThread(); }
Andre Eisenbach89ba5282016-10-13 15:45:02 -070071
72AsyncFdWatcher::~AsyncFdWatcher() {}
73
74// Make sure to call this with at least one file descriptor ready to be
75// watched upon or the thread routine will return immediately
76int AsyncFdWatcher::tryStartThread() {
77 if (std::atomic_exchange(&running_, true)) return 0;
78
79 // Set up the communication channel
80 int pipe_fds[2];
81 if (pipe2(pipe_fds, O_NONBLOCK)) return -1;
82
83 notification_listen_fd_ = pipe_fds[0];
84 notification_write_fd_ = pipe_fds[1];
85
86 thread_ = std::thread([this]() { ThreadRoutine(); });
87 if (!thread_.joinable()) return -1;
88
89 return 0;
90}
91
92int AsyncFdWatcher::stopThread() {
93 if (!std::atomic_exchange(&running_, false)) return 0;
94
95 notifyThread();
96 if (std::this_thread::get_id() != thread_.get_id()) {
97 thread_.join();
98 }
99
100 {
101 std::unique_lock<std::mutex> guard(internal_mutex_);
Myles Watsonf3a3cb72017-03-02 09:26:53 -0800102 watched_fds_.clear();
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700103 }
104
Myles Watson7d42dca2017-01-24 16:51:39 -0800105 {
106 std::unique_lock<std::mutex> guard(timeout_mutex_);
107 timeout_cb_ = nullptr;
108 }
109
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700110 return 0;
111}
112
113int AsyncFdWatcher::notifyThread() {
114 uint8_t buffer[] = {0};
115 if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
116 return -1;
117 }
118 return 0;
119}
120
121void AsyncFdWatcher::ThreadRoutine() {
Philip Cuadra8b3f3152017-04-20 16:02:48 -0700122 using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
123 using ::android::hardware::Return;
124 sp<ISchedulingPolicyService> manager = ISchedulingPolicyService::getService();
125 if (manager == nullptr) {
126 ALOGE("%s: Couldn't get scheduler manager to set SCHED_FIFO.", __func__);
127 } else {
128 Return<bool> ret = manager->requestPriority(getpid(),
129 gettid(),
130 BT_RT_PRIORITY);
131 if (!ret.isOk() || !ret) {
132 ALOGE("%s unable to set SCHED_FIFO for pid %d, tid %d", __func__,
133 getpid(), gettid());
134 }
135 }
136
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700137 while (running_) {
138 fd_set read_fds;
139 FD_ZERO(&read_fds);
140 FD_SET(notification_listen_fd_, &read_fds);
Myles Watsonf3a3cb72017-03-02 09:26:53 -0800141 int max_read_fd = INVALID_FD;
142 for (auto& it : watched_fds_) {
143 FD_SET(it.first, &read_fds);
144 max_read_fd = std::max(max_read_fd, it.first);
145 }
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700146
Myles Watson7d42dca2017-01-24 16:51:39 -0800147 struct timeval timeout;
148 struct timeval* timeout_ptr = NULL;
149 if (timeout_ms_ > std::chrono::milliseconds(0)) {
150 timeout.tv_sec = timeout_ms_.count() / 1000;
151 timeout.tv_usec = (timeout_ms_.count() % 1000) * 1000;
152 timeout_ptr = &timeout;
153 }
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700154
Myles Watson7d42dca2017-01-24 16:51:39 -0800155 // Wait until there is data available to read on some FD.
Myles Watsonf3a3cb72017-03-02 09:26:53 -0800156 int nfds = std::max(notification_listen_fd_, max_read_fd);
Myles Watson7d42dca2017-01-24 16:51:39 -0800157 int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr);
158
159 // There was some error.
160 if (retval < 0) continue;
161
162 // Timeout.
163 if (retval == 0) {
Myles Watsoneba13122017-02-02 10:47:36 -0800164 // Allow the timeout callback to modify the timeout.
165 TimeoutCallback saved_cb;
166 {
167 std::unique_lock<std::mutex> guard(timeout_mutex_);
168 if (timeout_ms_ > std::chrono::milliseconds(0))
169 saved_cb = timeout_cb_;
170 }
171 if (saved_cb != nullptr)
172 saved_cb();
Myles Watson7d42dca2017-01-24 16:51:39 -0800173 continue;
174 }
175
176 // Read data from the notification FD.
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700177 if (FD_ISSET(notification_listen_fd_, &read_fds)) {
178 char buffer[] = {0};
179 TEMP_FAILURE_RETRY(read(notification_listen_fd_, buffer, 1));
Myles Watson7d42dca2017-01-24 16:51:39 -0800180 continue;
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700181 }
182
Myles Watsonf3a3cb72017-03-02 09:26:53 -0800183 // Invoke the data ready callbacks if appropriate.
Myles Watsonf3a3cb72017-03-02 09:26:53 -0800184 {
Myles Watson9ef1f712017-03-09 10:39:31 -0800185 // Hold the mutex to make sure that the callbacks are still valid.
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700186 std::unique_lock<std::mutex> guard(internal_mutex_);
Myles Watsonf3a3cb72017-03-02 09:26:53 -0800187 for (auto& it : watched_fds_) {
188 if (FD_ISSET(it.first, &read_fds)) {
Myles Watsonf3a3cb72017-03-02 09:26:53 -0800189 it.second(it.first);
Myles Watson9ef1f712017-03-09 10:39:31 -0800190 }
Myles Watsonf3a3cb72017-03-02 09:26:53 -0800191 }
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700192 }
193 }
194}
195
Myles Watsonbe6176d2017-02-21 13:27:01 -0800196} // namespace async
Andre Eisenbach89ba5282016-10-13 15:45:02 -0700197} // namespace bluetooth
198} // namespace hardware
199} // namespace android