blob: 2cfcf9a3e74daa5544f9ac3fb05196bd4cf6dbcf [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVICES_BIN_DRIVER_MANAGER_DEVICE_WATCHER_H_
#define SRC_DEVICES_BIN_DRIVER_MANAGER_DEVICE_WATCHER_H_
#include <fcntl.h>
#include <fidl/fuchsia.device.manager/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fdio.h>
#include <zircon/errors.h>
#include <list>
#include "lib/fidl/llcpp/transaction.h"
#include "src/lib/fsl/io/device_watcher.h"
class DeviceWatcher : public fidl::WireServer<fuchsia_device_manager::DeviceWatcher> {
public:
DeviceWatcher(std::string dir_path, async_dispatcher_t* dispatcher) {
dir_path_ = std::move(dir_path);
dispatcher_ = dispatcher;
}
void NextDevice(NextDeviceRequestView request, NextDeviceCompleter::Sync& completer) override {
if (watcher_ == nullptr) {
fbl::unique_fd fd;
zx_status_t status =
fdio_open_fd(dir_path_.c_str(),
static_cast<uint32_t>(fuchsia_io::wire::OpenFlags::kRightWritable |
fuchsia_io::wire::OpenFlags::kRightReadable),
fd.reset_and_get_address());
if (status != ZX_OK) {
completer.ReplyError(status);
return;
}
watcher_ = fsl::DeviceWatcher::CreateWithIdleCallback(
std::move(fd), fit::bind_member<&DeviceWatcher::FdCallback>(this), [] {}, dispatcher_);
}
if (request_) {
completer.ReplyError(ZX_ERR_ALREADY_BOUND);
return;
}
if (channels_list_.empty()) {
request_ = completer.ToAsync();
return;
}
completer.ReplySuccess(std::move(channels_list_.front()));
channels_list_.pop_front();
}
private:
void FdCallback(int dir_fd, const std::string& filename) {
int fd = 0;
zx_status_t status = fdio_open_fd_at(dir_fd, filename.c_str(), O_RDONLY, &fd);
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to open device " << filename;
return;
}
zx::channel channel;
status = fdio_get_service_handle(fd, channel.reset_and_get_address());
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to get service handle " << filename;
return;
}
if (request_) {
request_->ReplySuccess(std::move(channel));
request_.reset();
return;
}
channels_list_.push_back(std::move(channel));
}
std::optional<NextDeviceCompleter::Async> request_;
std::unique_ptr<fsl::DeviceWatcher> watcher_;
std::list<zx::channel> channels_list_;
std::string dir_path_;
async_dispatcher_t* dispatcher_;
};
#endif // SRC_DEVICES_BIN_DRIVER_MANAGER_DEVICE_WATCHER_H_