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 2 M
getMemorySlot()52     virtual int getMemorySlot() override {
53         std::lock_guard<std::mutex> g{mMemoryMutex};
54         // when there are just 1 decoder, it can pretty
55         // much use all the memory starting from 0;
56         // when there are two, each can use at least half
57         // the total memory, etc.
58         constexpr size_t search_order[] = {
59                 0, // use 32M
60                 16, // use 16M
61                 8, 24, // use 8M
62                 4, 12, 20, 28, // use 4M
63                 2, 6, 10, 12, 18, 22, 26, 30, // use 2M
64                 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 // use 1M
65         };
66         for (size_t i = 0; i < sizeof(search_order)/sizeof(search_order[0]); ++i) {
67             int slot = search_order[i];
68             if (mMemoryLotsAvailable[slot]) {
69                 mMemoryLotsAvailable[slot] = false;
70                 return slot;
71             }
72         }
73         return -1;
74     }
returnMemorySlot(int lot)75     virtual void returnMemorySlot(int lot) override {
76         if (lot < 0 || lot >= mMemoryLotsAvailable.size()) {
77             return;
78         }
79         std::lock_guard<std::mutex> g{mMemoryMutex};
80         if (mMemoryLotsAvailable[lot] == false) {
81             mMemoryLotsAvailable[lot] = true;
82         } else {
83             ALOGE("Error, cannot twice");
84         }
85     }
86 private:
87     std::mutex mMemoryMutex;
88     std::vector<bool> mMemoryLotsAvailable = std::vector<bool>(32,true);
89 
90     address_space_handle_t mHandle;
91     uint64_t  mOffset;
92     uint64_t  mPhysAddr;
93     uint64_t  mSize;
94     void* mStartPtr = nullptr;
95 
96     // MediaCodecType will be or'd together with the metadata, so the highest 8-bits
97     // will have the type.
98     static __u64 makeMetadata(MediaCodecType type,
99                               MediaOperation op, uint64_t offset);
100 
101     // Chunk size for parameters/return data
102     static constexpr size_t kParamSizeBytes = 4096; // 4K
103     // Chunk size for input
104     static constexpr size_t kInputSizeBytes = 4096 * 4096; // 16M
105     // Chunk size for output
106     static constexpr size_t kOutputSizeBytes = 4096 * 4096; // 16M
107     // Maximum number of parameters that can be passed
108     static constexpr size_t kMaxParams = 32;
109     // Offset from the memory region for return data (8 is size of
110     // a parameter in bytes)
111     static constexpr size_t kReturnOffset = 8 * kMaxParams;
112 };
113 
~GoldfishMediaTransportImpl()114 GoldfishMediaTransportImpl::~GoldfishMediaTransportImpl() {
115   if(mHandle >= 0) {
116     goldfish_address_space_close(mHandle);
117     mHandle = -1;
118   }
119 }
120 
GoldfishMediaTransportImpl()121 GoldfishMediaTransportImpl::GoldfishMediaTransportImpl() {
122     // Allocate host memory; the contiguous memory region will be laid out as
123     // follows:
124     // ========================================================
125     // | kParamSizeBytes | kInputSizeBytes | kOutputSizeBytes |
126     // ========================================================
127     mHandle = goldfish_address_space_open();
128     if (mHandle < 0) {
129         ALOGE("Failed to ping host to allocate memory");
130         abort();
131     }
132     mSize = kParamSizeBytes + kInputSizeBytes + kOutputSizeBytes;
133     bool success = goldfish_address_space_allocate(mHandle, mSize, &mPhysAddr, &mOffset);
134     if (success) {
135         ALOGI("successfully allocated %d bytes in goldfish_address_block", (int)mSize);
136         mStartPtr = goldfish_address_space_map(mHandle, mOffset, mSize);
137         ALOGI("guest address is %p", mStartPtr);
138 
139         struct address_space_ping pingInfo;
140         pingInfo.metadata = GoldfishAddressSpaceSubdeviceType::Media;
141         pingInfo.offset = mOffset;
142         if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
143             ALOGE("Failed to ping host to allocate memory");
144             abort();
145             return;
146         } else {
147             ALOGI("successfully pinged host to allocate memory");
148         }
149     } else {
150         ALOGE("failed to allocate %d bytes in goldfish_address_block", (int)mSize);
151         abort();
152     }
153 }
154 
155 // static
getInstance()156 GoldfishMediaTransport* GoldfishMediaTransport::getInstance() {
157     std::lock_guard<std::mutex> g{sSingletonMutex};
158     if (sTransport == nullptr) {
159         sTransport.reset(new GoldfishMediaTransportImpl());
160     }
161     return sTransport.get();
162 }
163 
164 // static
makeMetadata(MediaCodecType type,MediaOperation op,uint64_t offset)165 __u64 GoldfishMediaTransportImpl::makeMetadata(MediaCodecType type,
166                                                MediaOperation op, uint64_t offset) {
167     // Shift |type| into the highest 8-bits, leaving the lower bits for other
168     // metadata.
169     offset = offset >> 20;
170     if (offset < 0 || offset >= 32) {
171         ALOGE("offset %d is wrong", (int)offset);
172         abort();
173     }
174     return ((__u64)type << (64 - 8)) | (offset << 8) | static_cast<uint8_t>(op);
175 }
176 
getInputAddr(unsigned int offSet) const177 uint8_t* GoldfishMediaTransportImpl::getInputAddr(unsigned int offSet) const {
178     return (uint8_t*)mStartPtr + kParamSizeBytes + offSet;
179 }
180 
getOutputAddr() const181 uint8_t* GoldfishMediaTransportImpl::getOutputAddr() const {
182     return getInputAddr() + kInputSizeBytes;
183 }
184 
getBaseAddr() const185 uint8_t* GoldfishMediaTransportImpl::getBaseAddr() const {
186     return (uint8_t*)mStartPtr;
187 }
188 
getReturnAddr(unsigned int offSet) const189 uint8_t* GoldfishMediaTransportImpl::getReturnAddr(unsigned int offSet) const {
190     return (uint8_t*)mStartPtr + kReturnOffset + offSet;
191 }
192 
offsetOf(uint64_t addr) const193 __u64 GoldfishMediaTransportImpl::offsetOf(uint64_t addr) const {
194     return addr - (uint64_t)mStartPtr;
195 }
196 
writeParam(__u64 val,unsigned int num,unsigned int offSetToStartAddr)197 void GoldfishMediaTransportImpl::writeParam(__u64 val, unsigned int num, unsigned int offSetToStartAddr) {
198     uint8_t* p = (uint8_t*)mStartPtr + (offSetToStartAddr);
199     uint64_t* pint = (uint64_t*)(p + 8 * num);
200     *pint = val;
201 }
202 
sendOperation(MediaCodecType type,MediaOperation op,unsigned int offSetToStartAddr)203 bool GoldfishMediaTransportImpl::sendOperation(MediaCodecType type,
204                                                MediaOperation op, unsigned int offSetToStartAddr) {
205     struct address_space_ping pingInfo;
206     pingInfo.metadata = makeMetadata(type, op, offSetToStartAddr);
207     pingInfo.offset = mOffset; // + (offSetToStartAddr);
208     if (goldfish_address_space_ping(mHandle, &pingInfo) == false) {
209         ALOGE("failed to ping host");
210         abort();
211         return false;
212     } else {
213         DDD("successfully pinged host for operation type=%d, op=%d", (int)type, (int)op);
214     }
215 
216     return true;
217 }
218