1 #ifndef ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
2 #define ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
3 
4 #include <assert.h>
5 #include <tuple>
6 
7 #include <libbroadcastring/broadcast_ring.h>
8 #include <private/dvr/display_client.h>
9 
10 namespace android {
11 namespace dvr {
12 
13 // The buffer usage type for mapped shared buffers.
14 enum class CPUUsageMode { READ_OFTEN, READ_RARELY, WRITE_OFTEN, WRITE_RARELY };
15 
16 // Holds the memory for the mapped shared buffer. Unlocks and releases the
17 // underlying IonBuffer in destructor.
18 class CPUMappedBuffer {
19  public:
20   // This constructor will create a display client and get the buffer from it.
21   CPUMappedBuffer(DvrGlobalBufferKey key, CPUUsageMode mode);
22 
23   // If you already have the IonBuffer, use this. It will take ownership.
24   CPUMappedBuffer(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode);
25 
26   // Use this if you do not want to take ownership.
27   CPUMappedBuffer(IonBuffer* buffer, CPUUsageMode mode);
28 
29   ~CPUMappedBuffer();
30 
31   // Getters.
Size()32   size_t Size() const { return size_; }
Address()33   void* Address() const { return address_; }
IsMapped()34   bool IsMapped() const { return Address() != nullptr; }
35 
36   // Attempt mapping this buffer to the CPU addressable space.
37   // This will create a display client and see if the buffer exists.
38   // If the buffer has not been setup yet, you will need to try again later.
39   void TryMapping();
40 
41  protected:
42   // The memory area if we managed to map it.
43   size_t size_ = 0;
44   void* address_ = nullptr;
45 
46   // If we are polling the display client, the buffer key here.
47   DvrGlobalBufferKey buffer_key_;
48 
49   // If we just own the IonBuffer outright, it's here.
50   std::unique_ptr<IonBuffer> owned_buffer_ = nullptr;
51 
52   // The last time we connected to the display service.
53   int64_t last_display_service_connection_ns_ = 0;
54 
55   // If we do not own the IonBuffer, it's here
56   IonBuffer* buffer_ = nullptr;
57 
58   // The usage mode.
59   CPUUsageMode usage_mode_ = CPUUsageMode::READ_OFTEN;
60 };
61 
62 // Represents a broadcast ring inside a mapped shared memory buffer.
63 // If has the same set of constructors as CPUMappedBuffer.
64 // The template argument is the concrete BroadcastRing class that this buffer
65 // holds.
66 template <class RingType>
67 class CPUMappedBroadcastRing : public CPUMappedBuffer {
68  public:
CPUMappedBroadcastRing(DvrGlobalBufferKey key,CPUUsageMode mode)69   CPUMappedBroadcastRing(DvrGlobalBufferKey key, CPUUsageMode mode)
70       : CPUMappedBuffer(key, mode) {}
71 
CPUMappedBroadcastRing(std::unique_ptr<IonBuffer> buffer,CPUUsageMode mode)72   CPUMappedBroadcastRing(std::unique_ptr<IonBuffer> buffer, CPUUsageMode mode)
73       : CPUMappedBuffer(std::move(buffer), mode) {}
74 
CPUMappedBroadcastRing(IonBuffer * buffer,CPUUsageMode mode)75   CPUMappedBroadcastRing(IonBuffer* buffer, CPUUsageMode mode)
76       : CPUMappedBuffer(buffer, mode) {}
77 
78   // Helper function for publishing records in the ring.
Publish(const typename RingType::Record & record)79   void Publish(const typename RingType::Record& record) {
80     assert((usage_mode_ == CPUUsageMode::WRITE_OFTEN) ||
81            (usage_mode_ == CPUUsageMode::WRITE_RARELY));
82 
83     auto ring = Ring();
84     if (ring) {
85       ring->Put(record);
86     }
87   }
88 
89   // Helper function for getting records from the ring.
90   // Returns true if we were able to retrieve the latest.
GetNewest(typename RingType::Record * record)91   bool GetNewest(typename RingType::Record* record) {
92     assert((usage_mode_ == CPUUsageMode::READ_OFTEN) ||
93            (usage_mode_ == CPUUsageMode::READ_RARELY));
94 
95     auto ring = Ring();
96     if (ring) {
97       return ring->GetNewest(&sequence_, record);
98     }
99 
100     return false;
101   }
102 
103   // Try obtaining the ring. If the named buffer has not been created yet, it
104   // will return nullptr.
Ring()105   RingType* Ring() {
106     // No ring created yet?
107     if (ring_ == nullptr) {
108       // Not mapped the memory yet?
109       if (IsMapped() == false) {
110         TryMapping();
111       }
112 
113       // If have the memory mapped, allocate the ring.
114       if (IsMapped()) {
115         switch (usage_mode_) {
116           case CPUUsageMode::READ_OFTEN:
117           case CPUUsageMode::READ_RARELY: {
118             RingType ring;
119             bool import_ok;
120             std::tie(ring, import_ok) = RingType::Import(address_, size_);
121             if (import_ok) {
122               ring_ = std::make_unique<RingType>(ring);
123             }
124           } break;
125           case CPUUsageMode::WRITE_OFTEN:
126           case CPUUsageMode::WRITE_RARELY:
127             ring_ =
128                 std::make_unique<RingType>(RingType::Create(address_, size_));
129             break;
130         }
131       }
132     }
133 
134     return ring_.get();
135   }
136 
137  protected:
138   std::unique_ptr<RingType> ring_ = nullptr;
139 
140   uint32_t sequence_ = 0;
141 };
142 
143 }  // namespace dvr
144 }  // namespace android
145 
146 #endif  // ANDROID_DVR_SHARED_BUFFER_HELPERS_H_
147