• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "RenderChannelImpl.h"
15 
16 #include "RenderThread.h"
17 #include "base/Lock.h"
18 
19 #include <algorithm>
20 #include <utility>
21 
22 #include <assert.h>
23 #include <string.h>
24 
25 #define EMUGL_DEBUG_LEVEL 0
26 #include "host-common/debug.h"
27 
28 namespace emugl {
29 
30 using Buffer = RenderChannel::Buffer;
31 using IoResult = android::base::BufferQueueResult;
32 using State = RenderChannel::State;
33 using AutoLock = android::base::AutoLock;
34 
35 // These constants correspond to the capacities of buffer queues
36 // used by each RenderChannelImpl instance. Benchmarking shows that
37 // it's important to have a large queue for guest -> host transfers,
38 // but a much smaller one works for host -> guest ones.
39 // Note: 32-bit Windows just doesn't have enough RAM to allocate optimal
40 // capacity.
41 #if defined(_WIN32) && !defined(_WIN64)
42 static constexpr size_t kGuestToHostQueueCapacity = 32U;
43 #else
44 static constexpr size_t kGuestToHostQueueCapacity = 1024U;
45 #endif
46 static constexpr size_t kHostToGuestQueueCapacity = 16U;
47 
RenderChannelImpl(android::base::Stream * loadStream)48 RenderChannelImpl::RenderChannelImpl(android::base::Stream* loadStream)
49     : mFromGuest(kGuestToHostQueueCapacity, mLock),
50       mToGuest(kHostToGuestQueueCapacity, mLock) {
51     if (loadStream) {
52         mFromGuest.onLoadLocked(loadStream);
53         mToGuest.onLoadLocked(loadStream);
54         mState = (State)loadStream->getBe32();
55         mWantedEvents = (State)loadStream->getBe32();
56 #ifndef NDEBUG
57         // Make sure we're in a consistent state after loading.
58         const auto state = mState;
59         updateStateLocked();
60         assert(state == mState);
61 #endif
62     } else {
63         updateStateLocked();
64     }
65     mRenderThread.reset(new RenderThread(this, loadStream));
66     mRenderThread->start();
67 }
68 
setEventCallback(EventCallback && callback)69 void RenderChannelImpl::setEventCallback(EventCallback&& callback) {
70     mEventCallback = std::move(callback);
71     notifyStateChangeLocked();
72 }
73 
setWantedEvents(State state)74 void RenderChannelImpl::setWantedEvents(State state) {
75     D("state=%d", (int)state);
76     AutoLock lock(mLock);
77     mWantedEvents |= state;
78     notifyStateChangeLocked();
79 }
80 
state() const81 RenderChannel::State RenderChannelImpl::state() const {
82     AutoLock lock(mLock);
83     return mState;
84 }
85 
tryWrite(Buffer && buffer)86 IoResult RenderChannelImpl::tryWrite(Buffer&& buffer) {
87     D("buffer size=%d", (int)buffer.size());
88     AutoLock lock(mLock);
89     auto result = mFromGuest.tryPushLocked(std::move(buffer));
90     updateStateLocked();
91     DD("mFromGuest.tryPushLocked() returned %d, state %d", (int)result,
92        (int)mState);
93     return result;
94 }
95 
tryRead(Buffer * buffer)96 IoResult RenderChannelImpl::tryRead(Buffer* buffer) {
97     D("enter");
98     AutoLock lock(mLock);
99     auto result = mToGuest.tryPopLocked(buffer);
100     updateStateLocked();
101     DD("mToGuest.tryPopLocked() returned %d, buffer size %d, state %d",
102        (int)result, (int)buffer->size(), (int)mState);
103     return result;
104 }
105 
readBefore(Buffer * buffer,Duration waitUntilUs)106 IoResult RenderChannelImpl::readBefore(Buffer* buffer, Duration waitUntilUs) {
107     D("enter");
108     AutoLock lock(mLock);
109     auto result = mToGuest.popLockedBefore(buffer, waitUntilUs);
110     updateStateLocked();
111     DD("mToGuest.popLockedBefore() returned %d, buffer size %d, state %d",
112        (int)result, (int)buffer->size(), (int)mState);
113     return result;
114 }
115 
stop()116 void RenderChannelImpl::stop() {
117     D("enter");
118     AutoLock lock(mLock);
119     mFromGuest.closeLocked();
120     mToGuest.closeLocked();
121     mEventCallback = [](State state) {};
122 }
123 
writeToGuest(Buffer && buffer)124 bool RenderChannelImpl::writeToGuest(Buffer&& buffer) {
125     D("buffer size=%d", (int)buffer.size());
126     AutoLock lock(mLock);
127     IoResult result = mToGuest.pushLocked(std::move(buffer));
128     updateStateLocked();
129     D("mToGuest.pushLocked() returned %d, state %d", (int)result, (int)mState);
130     notifyStateChangeLocked();
131     return result == IoResult::Ok;
132 }
133 
readFromGuest(Buffer * buffer,bool blocking)134 IoResult RenderChannelImpl::readFromGuest(Buffer* buffer, bool blocking) {
135     D("enter");
136     AutoLock lock(mLock);
137     IoResult result;
138     if (blocking) {
139         result = mFromGuest.popLocked(buffer);
140     } else {
141         result = mFromGuest.tryPopLocked(buffer);
142     }
143     updateStateLocked();
144     DD("mFromGuest.%s() return %d, buffer size %d, state %d",
145        blocking ? "popLocked" : "tryPopLocked", (int)result,
146        (int)buffer->size(), (int)mState);
147     notifyStateChangeLocked();
148     return result;
149 }
150 
stopFromHost()151 void RenderChannelImpl::stopFromHost() {
152     D("enter");
153 
154     AutoLock lock(mLock);
155     mFromGuest.closeLocked();
156     mToGuest.closeLocked();
157     mState |= State::Stopped;
158     notifyStateChangeLocked();
159     mEventCallback = [](State state) {};
160 }
161 
isStopped() const162 bool RenderChannelImpl::isStopped() const {
163     AutoLock lock(mLock);
164     return (mState & State::Stopped) != 0;
165 }
166 
renderThread() const167 RenderThread* RenderChannelImpl::renderThread() const {
168     return mRenderThread.get();
169 }
170 
pausePreSnapshot()171 void RenderChannelImpl::pausePreSnapshot() {
172     AutoLock lock(mLock);
173     mFromGuest.setSnapshotModeLocked(true);
174     mToGuest.setSnapshotModeLocked(true);
175 }
176 
resume()177 void RenderChannelImpl::resume() {
178     AutoLock lock(mLock);
179     mFromGuest.setSnapshotModeLocked(false);
180     mToGuest.setSnapshotModeLocked(false);
181 }
182 
~RenderChannelImpl()183 RenderChannelImpl::~RenderChannelImpl() {
184     // Make sure the render thread is stopped before the channel is gone.
185     mRenderThread->wait();
186 }
187 
updateStateLocked()188 void RenderChannelImpl::updateStateLocked() {
189     State state = RenderChannel::State::Empty;
190 
191     if (mToGuest.canPopLocked()) {
192         state |= State::CanRead;
193     }
194     if (mFromGuest.canPushLocked()) {
195         state |= State::CanWrite;
196     }
197     if (mToGuest.isClosedLocked()) {
198         state |= State::Stopped;
199     }
200     mState = state;
201 }
202 
notifyStateChangeLocked()203 void RenderChannelImpl::notifyStateChangeLocked() {
204     // Always report stop events, event if not explicitly asked for.
205     State available = mState & (mWantedEvents | State::Stopped);
206     if (available != 0) {
207         D("callback with %d", (int)available);
208         mWantedEvents &= ~mState;
209         mEventCallback(available);
210     }
211 }
212 
onSave(android::base::Stream * stream)213 void RenderChannelImpl::onSave(android::base::Stream* stream) {
214     D("enter");
215     AutoLock lock(mLock);
216     mFromGuest.onSaveLocked(stream);
217     mToGuest.onSaveLocked(stream);
218     stream->putBe32(static_cast<uint32_t>(mState));
219     stream->putBe32(static_cast<uint32_t>(mWantedEvents));
220     lock.unlock();
221     mRenderThread->save(stream);
222 }
223 
224 }  // namespace emugl
225