blob: b3c3ad7c8cf9955148b5a2c78ad6f1fb4ecdf79a [file] [log] [blame]
#include <fcntl.h>
#include <unistd.h>
#include <string>
namespace android {
namespace pdx {
enum class FileHandleMode {
// Manages ownership, sharing, and lifetime of file descriptors.
template <FileHandleMode Mode>
class FileHandle {
static constexpr int kEmptyFileHandle = -1;
// Constructs an empty FileHandle object.
FileHandle() : fd_(kEmptyFileHandle) {}
// Constructs a FileHandle from an integer file descriptor and takes
// ownership.
explicit FileHandle(int fd) : fd_(fd) {}
// Constructs a FileHandle by opening |path|. The arguments follow the
// semantics of open().
FileHandle(const std::string& path, int flags, mode_t mode = 0) {
fd_ = open(path.c_str(), flags, mode);
// Constructs a FileHandle by opening |path| relative to |dir_fd|, following
// the semantics of openat().
FileHandle(const int directory_fd, const std::string& path, int flags,
mode_t mode = 0) {
fd_ = openat(directory_fd, path.c_str(), flags, mode);
// Move constructor that assumes ownership of the file descriptor, leaving the
// other FileHandle object empty.
FileHandle(FileHandle&& other) {
fd_ = other.fd_;
other.fd_ = kEmptyFileHandle;
// Returns a FileHandle as a duplicate handle of |fd|. Borrowed handles and
// handles in remote handle space are not duplicated.
static FileHandle AsDuplicate(const int fd) {
if (Mode == FileHandleMode::Local)
return FileHandle(dup(fd));
return FileHandle(fd);
// Destructor closes the file descriptor when non-empty.
~FileHandle() { Close(); }
// Move assignment operator that assumes ownership of the underlying file
// descriptor, leaving the other FileHandle object empty.
FileHandle& operator=(FileHandle&& other) {
if (this != &other) {
other.fd_ = kEmptyFileHandle;
return *this;
// Resets the underlying file handle to |fd|.
void Reset(int fd) {
fd_ = fd;
// Closes the underlying file descriptor when non-empty.
void Close() {
if (IsValid() && Mode == FileHandleMode::Local)
fd_ = kEmptyFileHandle;
// Return the internal fd, passing ownership to the caller.
int Release() {
int release_fd = fd_;
fd_ = kEmptyFileHandle;
return release_fd;
// Duplicates the underlying file descriptor and returns a FileHandle that
// owns the new file descriptor. File descriptors are not duplicated when Mode
// is Remote or Borrowed.
FileHandle Duplicate() const {
return FileHandle(Mode == FileHandleMode::Local ? dup(fd_) : fd_);
FileHandle<FileHandleMode::Borrowed> Borrow() const {
return FileHandle<FileHandleMode::Borrowed>(Get());
// Gets the underlying file descriptor value.
int Get() const { return fd_; }
bool IsValid() const { return fd_ >= 0; }
explicit operator bool() const { return IsValid(); }
int fd_;
FileHandle(const FileHandle&) = delete;
void operator=(const FileHandle&) = delete;
// Alias for a file handle in the local process' handle space.
using LocalHandle = FileHandle<FileHandleMode::Local>;
// Alias for a file handle in another process' handle space. Handles returned
// from pushing a file object or channel must be stored in this type of handle
// class, which doesn't close the underlying file descriptor. The underlying
// file descriptor in this wrapper should not be passed to close() because doing
// so would close an unrelated file descriptor in the local handle space.
using RemoteHandle = FileHandle<FileHandleMode::Remote>;
// Alias for borrowed handles in the local process' handle space. A borrowed
// file handle is not close() because this wrapper does not own the underlying
// file descriptor. Care must be take to ensure that a borrowed file handle
// remains valid during use.
using BorrowedHandle = FileHandle<FileHandleMode::Borrowed>;
// FileReference is a 16 bit integer used in IPC serialization to be
// transferred across processes. You can convert this value to a local file
// handle by calling Transaction.GetFileHandle() on client side and
// Message.GetFileHandle() on service side.
using FileReference = int16_t;
} // namespace pdx
} // namespace android