1#ifndef ANDROID_PDX_FILE_HANDLE_H_
2#define ANDROID_PDX_FILE_HANDLE_H_
3
4#include <fcntl.h>
5#include <unistd.h>
6
7#include <string>
8
9namespace android {
10namespace pdx {
11
12enum class FileHandleMode {
13  Local,
14  Remote,
15  Borrowed,
16};
17
18// Manages ownership, sharing, and lifetime of file descriptors.
19template <FileHandleMode Mode>
20class FileHandle {
21 public:
22  static constexpr int kEmptyFileHandle = -1;
23
24  // Constructs an empty FileHandle object.
25  FileHandle() : fd_(kEmptyFileHandle) {}
26
27  // Constructs a FileHandle from an integer file descriptor and takes
28  // ownership.
29  explicit FileHandle(int fd) : fd_(fd) {}
30
31  // Constructs a FileHandle by opening |path|. The arguments follow the
32  // semantics of open().
33  FileHandle(const std::string& path, int flags, mode_t mode = 0) {
34    fd_ = open(path.c_str(), flags, mode);
35  }
36
37  // Constructs a FileHandle by opening |path| relative to |dir_fd|, following
38  // the semantics of openat().
39  FileHandle(const int directory_fd, const std::string& path, int flags,
40             mode_t mode = 0) {
41    fd_ = openat(directory_fd, path.c_str(), flags, mode);
42  }
43
44  // Move constructor that assumes ownership of the file descriptor, leaving the
45  // other FileHandle object empty.
46  FileHandle(FileHandle&& other) {
47    fd_ = other.fd_;
48    other.fd_ = kEmptyFileHandle;
49  }
50
51  // Returns a FileHandle as a duplicate handle of |fd|. Borrowed handles and
52  // handles in remote handle space are not duplicated.
53  static FileHandle AsDuplicate(const int fd) {
54    if (Mode == FileHandleMode::Local)
55      return FileHandle(dup(fd));
56    else
57      return FileHandle(fd);
58  }
59
60  // Destructor closes the file descriptor when non-empty.
61  ~FileHandle() { Close(); }
62
63  // Move assignment operator that assumes ownership of the underlying file
64  // descriptor, leaving the other FileHandle object empty.
65  FileHandle& operator=(FileHandle&& other) {
66    if (this != &other) {
67      Reset(other.fd_);
68      other.fd_ = kEmptyFileHandle;
69    }
70    return *this;
71  }
72
73  // Resets the underlying file handle to |fd|.
74  void Reset(int fd) {
75    Close();
76    fd_ = fd;
77  }
78
79  // Closes the underlying file descriptor when non-empty.
80  void Close() {
81    if (IsValid() && Mode == FileHandleMode::Local)
82      close(fd_);
83    fd_ = kEmptyFileHandle;
84  }
85
86  // Return the internal fd, passing ownership to the caller.
87  int Release() {
88    int release_fd = fd_;
89    fd_ = kEmptyFileHandle;
90    return release_fd;
91  }
92
93  // Duplicates the underlying file descriptor and returns a FileHandle that
94  // owns the new file descriptor. File descriptors are not duplicated when Mode
95  // is Remote or Borrowed.
96  FileHandle Duplicate() const {
97    return FileHandle(Mode == FileHandleMode::Local ? dup(fd_) : fd_);
98  }
99
100  FileHandle<FileHandleMode::Borrowed> Borrow() const {
101    return FileHandle<FileHandleMode::Borrowed>(Get());
102  }
103
104  // Gets the underlying file descriptor value.
105  int Get() const { return fd_; }
106  bool IsValid() const { return fd_ >= 0; }
107  explicit operator bool() const { return IsValid(); }
108
109 private:
110  int fd_;
111
112  FileHandle(const FileHandle&) = delete;
113  void operator=(const FileHandle&) = delete;
114};
115
116// Alias for a file handle in the local process' handle space.
117using LocalHandle = FileHandle<FileHandleMode::Local>;
118
119// Alias for a file handle in another process' handle space. Handles returned
120// from pushing a file object or channel must be stored in this type of handle
121// class, which doesn't close the underlying file descriptor. The underlying
122// file descriptor in this wrapper should not be passed to close() because doing
123// so would close an unrelated file descriptor in the local handle space.
124using RemoteHandle = FileHandle<FileHandleMode::Remote>;
125
126// Alias for borrowed handles in the local process' handle space. A borrowed
127// file handle is not close() because this wrapper does not own the underlying
128// file descriptor. Care must be take to ensure that a borrowed file handle
129// remains valid during use.
130using BorrowedHandle = FileHandle<FileHandleMode::Borrowed>;
131
132// FileReference is a 16 bit integer used in IPC serialization to be
133// transferred across processes. You can convert this value to a local file
134// handle by calling Transaction.GetFileHandle() on client side and
135// Message.GetFileHandle() on service side.
136using FileReference = int16_t;
137
138}  // namespace pdx
139}  // namespace android
140
141#endif  // ANDROID_PDX_FILE_HANDLE_H_
142