1 // Copyright (C) 2016 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 #include "ChannelStream.h"
15 
16 #include "render-utils/RenderChannel.h"
17 
18 #define EMUGL_DEBUG_LEVEL  0
19 #include "host-common/debug.h"
20 #include "host-common/dma_device.h"
21 #include "host-common/GfxstreamFatalError.h"
22 
23 #include <assert.h>
24 #include <memory.h>
25 
26 namespace gfxstream {
27 
28 using IoResult = RenderChannel::IoResult;
29 using emugl::ABORT_REASON_OTHER;
30 using emugl::FatalError;
31 
ChannelStream(RenderChannelImpl * channel,size_t bufSize)32 ChannelStream::ChannelStream(RenderChannelImpl* channel, size_t bufSize)
33     : IOStream(bufSize), mChannel(channel) {
34     mWriteBuffer.resize_noinit(bufSize);
35 }
36 
allocBuffer(size_t minSize)37 void* ChannelStream::allocBuffer(size_t minSize) {
38     if (mWriteBuffer.size() < minSize) {
39         mWriteBuffer.resize_noinit(minSize);
40     }
41     return mWriteBuffer.data();
42 }
43 
commitBuffer(size_t size)44 int ChannelStream::commitBuffer(size_t size) {
45     assert(size <= mWriteBuffer.size());
46     if (mWriteBuffer.isAllocated()) {
47         mWriteBuffer.resize(size);
48         mChannel->writeToGuest(std::move(mWriteBuffer));
49     } else {
50         mChannel->writeToGuest(
51                 RenderChannel::Buffer(mWriteBuffer.data(), mWriteBuffer.data() + size));
52     }
53     return size;
54 }
55 
readRaw(void * buf,size_t * inout_len)56 const unsigned char* ChannelStream::readRaw(void* buf, size_t* inout_len) {
57     size_t wanted = *inout_len;
58     size_t count = 0U;
59     auto dst = static_cast<uint8_t*>(buf);
60     D("wanted %d bytes", (int)wanted);
61     while (count < wanted) {
62         if (mReadBufferLeft > 0) {
63             size_t avail = std::min<size_t>(wanted - count, mReadBufferLeft);
64             memcpy(dst + count,
65                    mReadBuffer.data() + (mReadBuffer.size() - mReadBufferLeft),
66                    avail);
67             count += avail;
68             mReadBufferLeft -= avail;
69             continue;
70         }
71         bool blocking = (count == 0);
72         auto result = mChannel->readFromGuest(&mReadBuffer, blocking);
73         D("readFromGuest() returned %d, size %d", (int)result, (int)mReadBuffer.size());
74         if (result == IoResult::Ok) {
75             mReadBufferLeft = mReadBuffer.size();
76             continue;
77         }
78         if (count > 0) {  // There is some data to return.
79             break;
80         }
81         // Result can only be IoResult::Error if |count| == 0
82         // since |blocking| was true, it cannot be IoResult::TryAgain.
83         assert(result == IoResult::Error);
84         D("error while trying to read");
85         return nullptr;
86     }
87     *inout_len = count;
88     D("read %d bytes", (int)count);
89     return (const unsigned char*)buf;
90 }
91 
getDmaForReading(uint64_t guest_paddr)92 void* ChannelStream::getDmaForReading(uint64_t guest_paddr) {
93     return emugl::g_emugl_dma_get_host_addr(guest_paddr);
94 }
95 
unlockDma(uint64_t guest_paddr)96 void ChannelStream::unlockDma(uint64_t guest_paddr) { emugl::g_emugl_dma_unlock(guest_paddr); }
97 
forceStop()98 void ChannelStream::forceStop() {
99     mChannel->stopFromHost();
100 }
101 
writeFully(const void * buf,size_t len)102 int ChannelStream::writeFully(const void* buf, size_t len) {
103     void* dstBuf = alloc(len);
104     memcpy(dstBuf, buf, len);
105     flush();
106     return 0;
107 }
108 
readFully(void * buf,size_t len)109 const unsigned char *ChannelStream::readFully( void *buf, size_t len) {
110     GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
111         << "not intended for use with ChannelStream";
112 }
113 
onSave(android::base::Stream * stream)114 void ChannelStream::onSave(android::base::Stream* stream) {
115     // Write only the data that's left in read buffer, but in the same format
116     // as saveBuffer() does.
117     stream->putBe32(mReadBufferLeft);
118     stream->write(mReadBuffer.data() + mReadBuffer.size() - mReadBufferLeft,
119                   mReadBufferLeft);
120     android::base::saveBuffer(stream, mWriteBuffer);
121 }
122 
onLoad(android::base::Stream * stream)123 unsigned char* ChannelStream::onLoad(android::base::Stream* stream) {
124     android::base::loadBuffer(stream, &mReadBuffer);
125     mReadBufferLeft = mReadBuffer.size();
126     android::base::loadBuffer(stream, &mWriteBuffer);
127     return reinterpret_cast<unsigned char*>(mWriteBuffer.data());
128 }
129 
130 }  // namespace gfxstream
131