buffer_hub_client.h revision 2655e1cd5498749381701aa1fa7f29c66364a7ef
1#ifndef ANDROID_DVR_BUFFER_HUB_CLIENT_H_
2#define ANDROID_DVR_BUFFER_HUB_CLIENT_H_
3
4#include <hardware/gralloc.h>
5#include <pdx/channel_handle.h>
6#include <pdx/client.h>
7#include <pdx/file_handle.h>
8#include <pdx/status.h>
9
10#include <vector>
11
12#include <private/dvr/ion_buffer.h>
13
14namespace android {
15namespace dvr {
16
17class BufferHubBuffer : public pdx::Client {
18 public:
19  using LocalHandle = pdx::LocalHandle;
20  using LocalChannelHandle = pdx::LocalChannelHandle;
21  template <typename T>
22  using Status = pdx::Status<T>;
23
24  // Create a new consumer channel that is attached to the producer. Returns
25  // a file descriptor for the new channel or a negative error code.
26  Status<LocalChannelHandle> CreateConsumer();
27
28  // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
29  int Poll(int timeout_ms);
30
31  // Locks the area specified by (x, y, width, height) for a specific usage. If
32  // the usage is software then |addr| will be updated to point to the address
33  // of the buffer in virtual memory. The caller should only access/modify the
34  // pixels in the specified area. anything else is undefined behavior.
35  int Lock(int usage, int x, int y, int width, int height, void** addr,
36           size_t index);
37
38  // Must be called after Lock() when the caller has finished changing the
39  // buffer.
40  int Unlock(size_t index);
41
42  // Helper for when index is 0.
43  int Lock(int usage, int x, int y, int width, int height, void** addr) {
44    return Lock(usage, x, y, width, height, addr, 0);
45  }
46
47  // Helper for when index is 0.
48  int Unlock() { return Unlock(0); }
49
50  // Gets a blob buffer that was created with BufferProducer::CreateBlob.
51  // Locking and Unlocking is handled internally. There's no need to Unlock
52  // after calling this method.
53  int GetBlobReadWritePointer(size_t size, void** addr);
54
55  // Gets a blob buffer that was created with BufferProducer::CreateBlob.
56  // Locking and Unlocking is handled internally. There's no need to Unlock
57  // after calling this method.
58  int GetBlobReadOnlyPointer(size_t size, void** addr);
59
60  // Returns a dup'd file descriptor for accessing the blob shared memory. The
61  // caller takes ownership of the file descriptor and must close it or pass on
62  // ownership. Some GPU API extensions can take file descriptors to bind shared
63  // memory gralloc buffers to GPU buffer objects.
64  LocalHandle GetBlobFd() const {
65    // Current GPU vendor puts the buffer allocation in one FD. If we change GPU
66    // vendors and this is the wrong fd, late-latching and EDS will very clearly
67    // stop working and we will need to correct this. The alternative is to use
68    // a GL context in the pose service to allocate this buffer or to use the
69    // ION API directly instead of gralloc.
70    return LocalHandle(dup(native_handle()->data[0]));
71  }
72
73  // Get up to |max_fds_count| file descriptors for accessing the blob shared
74  // memory. |fds_count| will contain the actual number of file descriptors.
75  void GetBlobFds(int* fds, size_t* fds_count, size_t max_fds_count) const;
76
77  using Client::event_fd;
78
79  Status<int> GetEventMask(int events) {
80    if (auto* client_channel = GetChannel()) {
81      return client_channel->GetEventMask(events);
82    } else {
83      return pdx::ErrorStatus(EINVAL);
84    }
85  }
86
87  native_handle_t* native_handle() const {
88    return const_cast<native_handle_t*>(slices_[0].handle());
89  }
90  // If index is greater than or equal to slice_count(), the result is
91  // undefined.
92  native_handle_t* native_handle(size_t index) const {
93    return const_cast<native_handle_t*>(slices_[index].handle());
94  }
95
96  IonBuffer* buffer() { return &slices_[0]; }
97  const IonBuffer* buffer() const { return &slices_[0]; }
98
99  // If index is greater than or equal to slice_count(), the result is
100  // undefined.
101  IonBuffer* slice(size_t index) { return &slices_[index]; }
102  const IonBuffer* slice(size_t index) const { return &slices_[index]; }
103
104  int slice_count() const { return static_cast<int>(slices_.size()); }
105  int id() const { return id_; }
106
107  // The following methods return settings of the first buffer. Currently,
108  // it is only possible to create multi-buffer BufferHubBuffers with the same
109  // settings.
110  int width() const { return slices_[0].width(); }
111  int height() const { return slices_[0].height(); }
112  int stride() const { return slices_[0].stride(); }
113  int format() const { return slices_[0].format(); }
114  int usage() const { return slices_[0].usage(); }
115
116 protected:
117  explicit BufferHubBuffer(LocalChannelHandle channel);
118  explicit BufferHubBuffer(const std::string& endpoint_path);
119  virtual ~BufferHubBuffer();
120
121  // Initialization helper.
122  int ImportBuffer();
123
124 private:
125  BufferHubBuffer(const BufferHubBuffer&) = delete;
126  void operator=(const BufferHubBuffer&) = delete;
127
128  // Global id for the buffer that is consistent across processes. It is meant
129  // for logging and debugging purposes only and should not be used for lookup
130  // or any other functional purpose as a security precaution.
131  int id_;
132
133  // A BufferHubBuffer may contain multiple slices of IonBuffers with same
134  // configurations.
135  std::vector<IonBuffer> slices_;
136};
137
138// This represents a writable buffer. Calling Post notifies all clients and
139// makes the buffer read-only. Call Gain to acquire write access. A buffer
140// may have many consumers.
141//
142// The user of BufferProducer is responsible with making sure that the Post() is
143// done with the correct metadata type and size. The user is also responsible
144// for making sure that remote ends (BufferConsumers) are also using the correct
145// metadata when acquiring the buffer. The API guarantees that a Post() with a
146// metadata of wrong size will fail. However, it currently does not do any
147// type checking.
148// The API also assumes that metadata is a serializable type (plain old data).
149class BufferProducer : public pdx::ClientBase<BufferProducer, BufferHubBuffer> {
150 public:
151  // Create a buffer designed to hold arbitrary bytes that can be read and
152  // written from CPU, GPU and DSP. The buffer is mapped uncached so that CPU
153  // reads and writes are predictable.
154  static std::unique_ptr<BufferProducer> CreateUncachedBlob(size_t size);
155
156  // Creates a persistent uncached buffer with the given name and access.
157  static std::unique_ptr<BufferProducer> CreatePersistentUncachedBlob(
158      const std::string& name, int user_id, int group_id, size_t size);
159
160  // Imports a bufferhub producer channel, assuming ownership of its handle.
161  static std::unique_ptr<BufferProducer> Import(LocalChannelHandle channel);
162  static std::unique_ptr<BufferProducer> Import(
163      Status<LocalChannelHandle> status);
164
165  // Post this buffer, passing |ready_fence| to the consumers. The bytes in
166  // |meta| are passed unaltered to the consumers. The producer must not modify
167  // the buffer until it is re-gained.
168  // This returns zero or a negative unix error code.
169  int Post(const LocalHandle& ready_fence, const void* meta,
170           size_t meta_size_bytes);
171
172  template <typename Meta,
173            typename = typename std::enable_if<std::is_void<Meta>::value>::type>
174  int Post(const LocalHandle& ready_fence) {
175    return Post(ready_fence, nullptr, 0);
176  }
177  template <typename Meta, typename = typename std::enable_if<
178                               !std::is_void<Meta>::value>::type>
179  int Post(const LocalHandle& ready_fence, const Meta& meta) {
180    return Post(ready_fence, &meta, sizeof(meta));
181  }
182
183  // Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
184  // must be waited on before using the buffer. If it is not valid then the
185  // buffer is free for immediate use. This call will only succeed if the buffer
186  // is in the released state.
187  // This returns zero or a negative unix error code.
188  int Gain(LocalHandle* release_fence);
189
190  // Asynchronously marks a released buffer as gained. This method is similar to
191  // the synchronous version above, except that it does not wait for BufferHub
192  // to acknowledge success or failure, nor does it transfer a release fence to
193  // the client. This version may be used in situations where a release fence is
194  // not needed. Because of the asynchronous nature of the underlying message,
195  // no error is returned if this method is called when the buffer is in an
196  // incorrect state. Returns zero if sending the message succeeded, or a
197  // negative errno code otherwise.
198  int GainAsync();
199
200  // Attaches the producer to |name| so that it becomes a persistent buffer that
201  // may be retrieved by name at a later time. This may be used in cases where a
202  // shared memory buffer should persist across the life of the producer process
203  // (i.e. the buffer may be held by clients across a service restart). The
204  // buffer may be associated with a user and/or group id to restrict access to
205  // the buffer. If user_id or group_id is -1 then checks for the respective id
206  // are disabled. If user_id or group_id is 0 then the respective id of the
207  // calling process is used instead.
208  int MakePersistent(const std::string& name, int user_id, int group_id);
209
210  // Removes the persistence of the producer.
211  int RemovePersistence();
212
213 private:
214  friend BASE;
215
216  // Constructors are automatically exposed through BufferProducer::Create(...)
217  // static template methods inherited from ClientBase, which take the same
218  // arguments as the constructors.
219
220  // Constructs a buffer with the given geometry and parameters.
221  BufferProducer(int width, int height, int format, int usage,
222                 size_t metadata_size = 0, size_t slice_count = 1);
223
224  // Constructs a persistent buffer with the given geometry and parameters and
225  // binds it to |name| in one shot. If a persistent buffer with the same name
226  // and settings already exists and matches the given geometry and parameters,
227  // that buffer is connected to this client instead of creating a new buffer.
228  // If the name matches but the geometry or settings do not match then
229  // construction fails and BufferProducer::Create() returns nullptr.
230  //
231  // Access to the persistent buffer may be restricted by |user_id| and/or
232  // |group_id|; these settings are established only when the buffer is first
233  // created and cannot be changed. A user or group id of -1 disables checks for
234  // that respective id. A user or group id of 0 is substituted with the
235  // effective user or group id of the calling process.
236  BufferProducer(const std::string& name, int user_id, int group_id, int width,
237                 int height, int format, int usage, size_t metadata_size = 0,
238                 size_t slice_count = 1);
239
240  // Constructs a blob (flat) buffer with the given usage flags.
241  BufferProducer(int usage, size_t size);
242
243  // Constructs a persistent blob (flat) buffer and binds it to |name|.
244  BufferProducer(const std::string& name, int user_id, int group_id, int usage,
245                 size_t size);
246
247  // Constructs a channel to persistent buffer by name only. The buffer must
248  // have been previously created or made persistent.
249  explicit BufferProducer(const std::string& name);
250
251  // Imports the given file handle to a producer channel, taking ownership.
252  explicit BufferProducer(LocalChannelHandle channel);
253};
254
255// This is a connection to a producer buffer, which can be located in another
256// application. When that buffer is Post()ed, this fd will be signaled and
257// Acquire allows read access. The user is responsible for making sure that
258// Acquire is called with the correct metadata structure. The only guarantee the
259// API currently provides is that an Acquire() with metadata of the wrong size
260// will fail.
261class BufferConsumer : public pdx::ClientBase<BufferConsumer, BufferHubBuffer> {
262 public:
263  // This call assumes ownership of |fd|.
264  static std::unique_ptr<BufferConsumer> Import(LocalChannelHandle channel);
265  static std::unique_ptr<BufferConsumer> Import(
266      Status<LocalChannelHandle> status);
267
268  // Attempt to retrieve a post event from buffer hub. If successful,
269  // |ready_fence| will be set to a fence to wait on until the buffer is ready.
270  // This call will only succeed after the fd is signalled. This call may be
271  // performed as an alternative to the Acquire() with metadata. In such cases
272  // the metadata is not read.
273  //
274  // This returns zero or negative unix error code.
275  int Acquire(LocalHandle* ready_fence);
276
277  // Attempt to retrieve a post event from buffer hub. If successful,
278  // |ready_fence| is set to a fence signaling that the contents of the buffer
279  // are available. This call will only succeed if the buffer is in the posted
280  // state.
281  // Returns zero on success, or a negative errno code otherwise.
282  int Acquire(LocalHandle* ready_fence, void* meta, size_t meta_size_bytes);
283
284  // Attempt to retrieve a post event from buffer hub. If successful,
285  // |ready_fence| is set to a fence to wait on until the buffer is ready. This
286  // call will only succeed after the fd is signaled. This returns zero or a
287  // negative unix error code.
288  template <typename Meta>
289  int Acquire(LocalHandle* ready_fence, Meta* meta) {
290    return Acquire(ready_fence, meta, sizeof(*meta));
291  }
292
293  // This should be called after a successful Acquire call. If the fence is
294  // valid the fence determines the buffer usage, otherwise the buffer is
295  // released immediately.
296  // This returns zero or a negative unix error code.
297  int Release(const LocalHandle& release_fence);
298
299  // Asynchronously releases a buffer. Similar to the synchronous version above,
300  // except that it does not wait for BufferHub to reply with success or error,
301  // nor does it transfer a release fence. This version may be used in
302  // situations where a release fence is not needed. Because of the asynchronous
303  // nature of the underlying message, no error is returned if this method is
304  // called when the buffer is in an incorrect state. Returns zero if sending
305  // the message succeeded, or a negative errno code otherwise.
306  int ReleaseAsync();
307
308  // May be called after or instead of Acquire to indicate that the consumer
309  // does not need to access the buffer this cycle. This returns zero or a
310  // negative unix error code.
311  int Discard();
312
313  // When set, this consumer is no longer notified when this buffer is
314  // available. The system behaves as if Discard() is immediately called
315  // whenever the buffer is posted. If ignore is set to true while a buffer is
316  // pending, it will act as if Discard() was also called.
317  // This returns zero or a negative unix error code.
318  int SetIgnore(bool ignore);
319
320 private:
321  friend BASE;
322
323  explicit BufferConsumer(LocalChannelHandle channel);
324};
325
326}  // namespace dvr
327}  // namespace android
328
329#endif  // ANDROID_DVR_BUFFER_HUB_CLIENT_H_
330