142 lines
4.3 KiB
C
142 lines
4.3 KiB
C
|
#ifndef ANDROID_PDX_FILE_HANDLE_H_
|
||
|
#define ANDROID_PDX_FILE_HANDLE_H_
|
||
|
|
||
|
#include <fcntl.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <string>
|
||
|
|
||
|
namespace android {
|
||
|
namespace pdx {
|
||
|
|
||
|
enum class FileHandleMode {
|
||
|
Local,
|
||
|
Remote,
|
||
|
Borrowed,
|
||
|
};
|
||
|
|
||
|
// Manages ownership, sharing, and lifetime of file descriptors.
|
||
|
template <FileHandleMode Mode>
|
||
|
class FileHandle {
|
||
|
public:
|
||
|
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) noexcept {
|
||
|
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));
|
||
|
else
|
||
|
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) noexcept {
|
||
|
if (this != &other) {
|
||
|
Reset(other.fd_);
|
||
|
other.fd_ = kEmptyFileHandle;
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
// Resets the underlying file handle to |fd|.
|
||
|
void Reset(int fd) {
|
||
|
Close();
|
||
|
fd_ = fd;
|
||
|
}
|
||
|
|
||
|
// Closes the underlying file descriptor when non-empty.
|
||
|
void Close() {
|
||
|
if (IsValid() && Mode == FileHandleMode::Local)
|
||
|
close(fd_);
|
||
|
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(); }
|
||
|
|
||
|
private:
|
||
|
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
|
||
|
|
||
|
#endif // ANDROID_PDX_FILE_HANDLE_H_
|