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 
9 namespace android {
10 namespace pdx {
11 
12 enum class FileHandleMode {
13   Local,
14   Remote,
15   Borrowed,
16 };
17 
18 // Manages ownership, sharing, and lifetime of file descriptors.
19 template <FileHandleMode Mode>
20 class FileHandle {
21  public:
22   static constexpr int kEmptyFileHandle = -1;
23 
24   // Constructs an empty FileHandle object.
FileHandle()25   FileHandle() : fd_(kEmptyFileHandle) {}
26 
27   // Constructs a FileHandle from an integer file descriptor and takes
28   // ownership.
FileHandle(int fd)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.
FileHandle(FileHandle && other)46   FileHandle(FileHandle&& other) noexcept {
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.
AsDuplicate(const int fd)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.
~FileHandle()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) noexcept {
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|.
Reset(int fd)74   void Reset(int fd) {
75     Close();
76     fd_ = fd;
77   }
78 
79   // Closes the underlying file descriptor when non-empty.
Close()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.
Release()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.
Duplicate()96   FileHandle Duplicate() const {
97     return FileHandle(Mode == FileHandleMode::Local ? dup(fd_) : fd_);
98   }
99 
Borrow()100   FileHandle<FileHandleMode::Borrowed> Borrow() const {
101     return FileHandle<FileHandleMode::Borrowed>(Get());
102   }
103 
104   // Gets the underlying file descriptor value.
Get()105   int Get() const { return fd_; }
IsValid()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.
117 using 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.
124 using 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.
130 using 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.
136 using FileReference = int16_t;
137 
138 }  // namespace pdx
139 }  // namespace android
140 
141 #endif  // ANDROID_PDX_FILE_HANDLE_H_
142