1 // Copyright 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "goldfish_media_utils.h"
16 
17 #include "goldfish_address_space.h"
18 
19 #include <log/log.h>
20 
21 #define DEBUG  0
22 #if DEBUG
23 #  define  DDD(...)    ALOGD(__VA_ARGS__)
24 #else
25 #  define  DDD(...)    ((void)0)
26 #endif
27 
28 #include <memory>
29 #include <vector>
30 #include <mutex>
31 
32 
33 
34 std::mutex sSingletonMutex;
35 std::unique_ptr<GoldfishMediaTransport> sTransport;
36 
37 class GoldfishMediaTransportImpl : public GoldfishMediaTransport {
38 public:
39     GoldfishMediaTransportImpl();
40     ~GoldfishMediaTransportImpl();
41 
42     virtual void writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr = 0) override;
43     virtual bool sendOperation(MediaCodecType type, MediaOperation op, unsigned int offSetToStartAddr = 0) override;
44     virtual uint8_t* getBaseAddr() const override;
45     virtual uint8_t* getInputAddr(unsigned int offSet = 0) const override;
46     virtual uint8_t* getOutputAddr() const override;
47     virtual uint8_t* getReturnAddr(unsigned int offSet = 0) const override;
48     virtual __u64 offsetOf(uint64_t addr) const override;
49 
50 public:
51     // each lot has 8 M
getMemorySlot()52     virtual int getMemorySlot() override {
53         std::lock_guard<std::mutex> g{mMemoryMutex};
54         for (int i = mMemoryLotsAvailable.size() - 1; i >=0 ; --i) {
55             if (mMemoryLotsAvailable[i]) {
56                 mMemoryLotsAvailable[i] = false;
57                 return i;
58             }
59         }
60         return -1;
61     }
returnMemorySlot(int lot)62     virtual void returnMemorySlot(int lot) override {
63         if (lot < 0 || lot >= mMemoryLotsAvailable.size()) {
64             return;
65         }
66         std::lock_guard<std::mutex> g{mMemoryMutex};
67         if (mMemoryLotsAvailable[lot] == false) {
68             mMemoryLotsAvailable[lot] = true;
69         } else {
70             ALOGE("Error, cannot twice");
71         }
72     }
73 private:
74     std::mutex mMemoryMutex;
75     std::vector<bool> mMemoryLotsAvailable = {true, true, true, true};
76 
77     address_space_handle_t mHandle;
78     uint64_t  mOffset;
79     uint64_t  mPhysAddr;
80     uint64_t  mSize;
81     void* mStartPtr = nullptr;
82 
83     // MediaCodecType will be or'd together with the metadata, so the highest 8-bits
84     // will have the type.
85     static __u64 makeMetadata(MediaCodecType type,
86                               MediaOperation op, uint64_t offset);
87 
88     // Chunk size for parameters/return data
89     static constexpr size_t kParamSizeBytes = 4096; // 4K
90     // Chunk size for input
91     static constexpr size_t kInputSizeBytes = 4096 * 4096; // 16M
92     // Chunk size for output
93     static constexpr size_t kOutputSizeBytes = 4096 * 4096; // 16M
94     // Maximum number of parameters that can be passed
95     static constexpr size_t kMaxParams = 32;
96     // Offset from the memory region for return data (8 is size of
97     // a parameter in bytes)
98     static constexpr size_t kReturnOffset = 8 * kMaxParams;
99 };
100 
~GoldfishMediaTransportImpl()101 GoldfishMediaTransportImpl::~GoldfishMediaTransportImpl() {
102   if(mHandle >= 0) {
103     goldfish_address_space_close(mHandle);
104     mHandle = -1;
105   }
106 }
107 
GoldfishMediaTransportImpl()108 GoldfishMediaTransportImpl::GoldfishMediaTransportImpl() {
109     // Allocate host memory; the contiguous memory region will be laid out as
110     // follows:
111     // ========================================================
112     // | kParamSizeBytes | kInputSizeBytes | kOutputSizeBytes |
113     // ========================================================
114     mHandle = goldfish_address_space_open();
115     if (mHandle < 0) {
116         ALOGE("Failed to ping host to allocate memory");
117         abort();
118     }
119     mSize = kParamSizeBytes + kInputSizeBytes + kOutputSizeBytes;
120     bool success = goldfish_address_space_allocate(mHandle, mSize, &mPhysAddr, &mOffset);
121     if (success) {
122         ALOGI("successfully allocated %d bytes in goldfish_address_block", (int)mSize);
123         mStartPtr = goldfish_address_space_map(mHandle, mOffset, mSize);
124         ALOGI("guest address is %p", mStartPtr);
125 
126         struct address_space_ping pingInfo;
127         pingInfo.metadata = GoldfishAddressSpaceSubdeviceType::Media;
128         pingInfo.offset = mOffset;
129         if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
130             ALOGE("Failed to ping host to allocate memory");
131             abort();
132             return;
133         } else {
134             ALOGI("successfully pinged host to allocate memory");
135         }
136     } else {
137         ALOGE("failed to allocate %d bytes in goldfish_address_block", (int)mSize);
138         abort();
139     }
140 }
141 
142 // static
getInstance()143 GoldfishMediaTransport* GoldfishMediaTransport::getInstance() {
144     std::lock_guard<std::mutex> g{sSingletonMutex};
145     if (sTransport == nullptr) {
146         sTransport.reset(new GoldfishMediaTransportImpl());
147     }
148     return sTransport.get();
149 }
150 
151 // static
makeMetadata(MediaCodecType type,MediaOperation op,uint64_t offset)152 __u64 GoldfishMediaTransportImpl::makeMetadata(MediaCodecType type,
153                                                MediaOperation op, uint64_t offset) {
154     // Shift |type| into the highest 8-bits, leaving the lower bits for other
155     // metadata.
156     offset = offset >> 20;
157     return ((__u64)type << (64 - 8)) | (offset << 8) | static_cast<uint8_t>(op);
158 }
159 
getInputAddr(unsigned int offSet) const160 uint8_t* GoldfishMediaTransportImpl::getInputAddr(unsigned int offSet) const {
161     return (uint8_t*)mStartPtr + kParamSizeBytes + offSet;
162 }
163 
getOutputAddr() const164 uint8_t* GoldfishMediaTransportImpl::getOutputAddr() const {
165     return getInputAddr() + kInputSizeBytes;
166 }
167 
getBaseAddr() const168 uint8_t* GoldfishMediaTransportImpl::getBaseAddr() const {
169     return (uint8_t*)mStartPtr;
170 }
171 
getReturnAddr(unsigned int offSet) const172 uint8_t* GoldfishMediaTransportImpl::getReturnAddr(unsigned int offSet) const {
173     return (uint8_t*)mStartPtr + kReturnOffset + offSet;
174 }
175 
offsetOf(uint64_t addr) const176 __u64 GoldfishMediaTransportImpl::offsetOf(uint64_t addr) const {
177     return addr - (uint64_t)mStartPtr;
178 }
179 
writeParam(__u64 val,unsigned int num,unsigned int offSetToStartAddr)180 void GoldfishMediaTransportImpl::writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr) {
181     uint8_t* p = (uint8_t*)mStartPtr + (offSetToStartAddr);
182     uint64_t* pint = (uint64_t*)(p + 8 * num);
183     *pint = val;
184 }
185 
sendOperation(MediaCodecType type,MediaOperation op,unsigned int offSetToStartAddr)186 bool GoldfishMediaTransportImpl::sendOperation(MediaCodecType type,
187                                                MediaOperation op, unsigned int offSetToStartAddr) {
188     struct address_space_ping pingInfo;
189     pingInfo.metadata = makeMetadata(type, op, offSetToStartAddr);
190     pingInfo.offset = mOffset; // + (offSetToStartAddr);
191     if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
192         ALOGE("failed to ping host");
193         abort();
194         return false;
195     } else {
196         DDD("successfully pinged host for operation type=%d, op=%d", (int)type, (int)op);
197     }
198 
199     return true;
200 }
201