1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "AddressSpaceStream.h"
17 
18 #if PLATFORM_SDK_VERSION < 26
19 #include <cutils/log.h>
20 #else
21 #include <log/log.h>
22 #endif
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 
29 static const size_t kReadSize = 512 * 1024;
30 static const size_t kWriteOffset = kReadSize;
31 
createAddressSpaceStream(size_t ignored_bufSize)32 AddressSpaceStream* createAddressSpaceStream(size_t ignored_bufSize) {
33     // Ignore incoming ignored_bufSize
34     (void)ignored_bufSize;
35 
36     auto handle = goldfish_address_space_open();
37     address_space_handle_t child_device_handle;
38 
39     if (!goldfish_address_space_set_subdevice_type(handle, GoldfishAddressSpaceSubdeviceType::Graphics, &child_device_handle)) {
40         ALOGE("AddressSpaceStream::create failed (initial device create)\n");
41         goldfish_address_space_close(handle);
42         return nullptr;
43     }
44 
45     struct goldfish_address_space_ping request;
46     request.metadata = ASG_GET_RING;
47     if (!goldfish_address_space_ping(child_device_handle, &request)) {
48         ALOGE("AddressSpaceStream::create failed (get ring)\n");
49         goldfish_address_space_close(child_device_handle);
50         return nullptr;
51     }
52 
53     uint64_t ringOffset = request.metadata;
54 
55     request.metadata = ASG_GET_BUFFER;
56     if (!goldfish_address_space_ping(child_device_handle, &request)) {
57         ALOGE("AddressSpaceStream::create failed (get buffer)\n");
58         goldfish_address_space_close(child_device_handle);
59         return nullptr;
60     }
61 
62     uint64_t bufferOffset = request.metadata;
63     uint64_t bufferSize = request.size;
64 
65     if (!goldfish_address_space_claim_shared(
66         child_device_handle, ringOffset, sizeof(asg_ring_storage))) {
67         ALOGE("AddressSpaceStream::create failed (claim ring storage)\n");
68         goldfish_address_space_close(child_device_handle);
69         return nullptr;
70     }
71 
72     if (!goldfish_address_space_claim_shared(
73         child_device_handle, bufferOffset, bufferSize)) {
74         ALOGE("AddressSpaceStream::create failed (claim buffer storage)\n");
75         goldfish_address_space_unclaim_shared(child_device_handle, ringOffset);
76         goldfish_address_space_close(child_device_handle);
77         return nullptr;
78     }
79 
80     char* ringPtr = (char*)goldfish_address_space_map(
81         child_device_handle, ringOffset, sizeof(struct asg_ring_storage));
82 
83     if (!ringPtr) {
84         ALOGE("AddressSpaceStream::create failed (map ring storage)\n");
85         goldfish_address_space_unclaim_shared(child_device_handle, bufferOffset);
86         goldfish_address_space_unclaim_shared(child_device_handle, ringOffset);
87         goldfish_address_space_close(child_device_handle);
88         return nullptr;
89     }
90 
91     char* bufferPtr = (char*)goldfish_address_space_map(
92         child_device_handle, bufferOffset, bufferSize);
93 
94     if (!bufferPtr) {
95         ALOGE("AddressSpaceStream::create failed (map buffer storage)\n");
96         goldfish_address_space_unmap(ringPtr, sizeof(struct asg_ring_storage));
97         goldfish_address_space_unclaim_shared(child_device_handle, bufferOffset);
98         goldfish_address_space_unclaim_shared(child_device_handle, ringOffset);
99         goldfish_address_space_close(child_device_handle);
100         return nullptr;
101     }
102 
103     struct asg_context context =
104         asg_context_create(
105             ringPtr, bufferPtr, bufferSize);
106 
107     request.metadata = ASG_SET_VERSION;
108     request.size = 1; // version 1
109 
110     if (!goldfish_address_space_ping(child_device_handle, &request)) {
111         ALOGE("AddressSpaceStream::create failed (get buffer)\n");
112         goldfish_address_space_unmap(bufferPtr, bufferSize);
113         goldfish_address_space_unmap(ringPtr, sizeof(struct asg_ring_storage));
114         goldfish_address_space_unclaim_shared(child_device_handle, bufferOffset);
115         goldfish_address_space_unclaim_shared(child_device_handle, ringOffset);
116         goldfish_address_space_close(child_device_handle);
117         return nullptr;
118     }
119 
120     uint32_t version = request.size;
121 
122     context.ring_config->transfer_mode = 1;
123     context.ring_config->host_consumed_pos = 0;
124     context.ring_config->guest_write_pos = 0;
125 
126     AddressSpaceStream* res =
127         new AddressSpaceStream(
128             child_device_handle, version, context,
129             ringOffset, bufferOffset);
130 
131     return res;
132 }
133 
AddressSpaceStream(address_space_handle_t handle,uint32_t version,struct asg_context context,uint64_t ringOffset,uint64_t writeBufferOffset)134 AddressSpaceStream::AddressSpaceStream(
135     address_space_handle_t handle,
136     uint32_t version,
137     struct asg_context context,
138     uint64_t ringOffset,
139     uint64_t writeBufferOffset) :
140     IOStream(context.ring_config->flush_interval),
141     m_tmpBuf(0),
142     m_tmpBufSize(0),
143     m_tmpBufXferSize(0),
144     m_usingTmpBuf(0),
145     m_readBuf(0),
146     m_read(0),
147     m_readLeft(0),
148     m_handle(handle),
149     m_version(version),
150     m_context(context),
151     m_ringOffset(ringOffset),
152     m_writeBufferOffset(writeBufferOffset),
153     m_writeBufferSize(context.ring_config->buffer_size),
154     m_writeBufferMask(m_writeBufferSize - 1),
155     m_buf((unsigned char*)context.buffer),
156     m_writeStart(m_buf),
157     m_writeStep(context.ring_config->flush_interval),
158     m_notifs(0),
159     m_written(0) {
160     // We'll use this in the future, but at the moment,
161     // it's a potential compile Werror.
162     (void)m_version;
163 }
164 
~AddressSpaceStream()165 AddressSpaceStream::~AddressSpaceStream() {
166     goldfish_address_space_unmap(m_context.to_host, sizeof(struct asg_ring_storage));
167     goldfish_address_space_unmap(m_context.buffer, m_writeBufferSize);
168     goldfish_address_space_unclaim_shared(m_handle, m_ringOffset);
169     goldfish_address_space_unclaim_shared(m_handle, m_writeBufferOffset);
170     goldfish_address_space_close(m_handle);
171     if (m_readBuf) free(m_readBuf);
172     if (m_tmpBuf) free(m_tmpBuf);
173 }
174 
idealAllocSize(size_t len)175 size_t AddressSpaceStream::idealAllocSize(size_t len) {
176     if (len > m_writeStep) return len;
177     return m_writeStep;
178 }
179 
allocBuffer(size_t minSize)180 void *AddressSpaceStream::allocBuffer(size_t minSize) {
181     if (!m_readBuf) {
182         m_readBuf = (unsigned char*)malloc(kReadSize);
183     }
184 
185     size_t allocSize =
186         (m_writeStep < minSize ? minSize : m_writeStep);
187 
188     if (m_writeStep < allocSize) {
189         if (!m_tmpBuf) {
190             m_tmpBufSize = allocSize * 2;
191             m_tmpBuf = (unsigned char*)malloc(m_tmpBufSize);
192         }
193 
194         if (m_tmpBufSize < allocSize) {
195             m_tmpBufSize = allocSize * 2;
196             m_tmpBuf = (unsigned char*)realloc(m_tmpBuf, m_tmpBufSize);
197         }
198 
199         if (!m_usingTmpBuf) {
200             flush();
201         }
202 
203         m_usingTmpBuf = true;
204         m_tmpBufXferSize = allocSize;
205         return m_tmpBuf;
206     } else {
207         if (m_usingTmpBuf) {
208             writeFully(m_tmpBuf, m_tmpBufXferSize);
209             m_usingTmpBuf = false;
210             m_tmpBufXferSize = 0;
211         }
212 
213         return m_writeStart;
214     }
215 };
216 
commitBuffer(size_t size)217 int AddressSpaceStream::commitBuffer(size_t size)
218 {
219     if (size == 0) return 0;
220 
221     if (m_usingTmpBuf) {
222         writeFully(m_tmpBuf, size);
223         m_tmpBufXferSize = 0;
224         m_usingTmpBuf = false;
225         return 0;
226     } else {
227         int res = type1Write(m_writeStart - m_buf, size);
228         advanceWrite();
229         return res;
230     }
231 }
232 
readFully(void * ptr,size_t totalReadSize)233 const unsigned char *AddressSpaceStream::readFully(void *ptr, size_t totalReadSize)
234 {
235 
236     unsigned char* userReadBuf = static_cast<unsigned char*>(ptr);
237 
238     if (!userReadBuf) {
239         if (totalReadSize > 0) {
240             ALOGE("AddressSpaceStream::commitBufferAndReadFully failed, userReadBuf=NULL, totalReadSize %zu, lethal"
241                     " error, exiting.", totalReadSize);
242             abort();
243         }
244         return nullptr;
245     }
246 
247     // Advance buffered read if not yet consumed.
248     size_t remaining = totalReadSize;
249     size_t bufferedReadSize =
250         m_readLeft < remaining ? m_readLeft : remaining;
251 
252     if (bufferedReadSize) {
253         memcpy(userReadBuf,
254                m_readBuf + (m_read - m_readLeft),
255                bufferedReadSize);
256         remaining -= bufferedReadSize;
257         m_readLeft -= bufferedReadSize;
258     }
259 
260     if (!remaining) return userReadBuf;
261 
262     // Read up to kReadSize bytes if all buffered read has been consumed.
263     size_t maxRead = m_readLeft ? 0 : kReadSize;
264     ssize_t actual = 0;
265 
266     if (maxRead) {
267         actual = speculativeRead(m_readBuf, maxRead);
268 
269         // Updated buffered read size.
270         if (actual > 0) {
271             m_read = m_readLeft = actual;
272         }
273 
274         if (actual == 0) {
275             ALOGD("%s: end of pipe", __FUNCTION__);
276             return NULL;
277         }
278     }
279 
280     // Consume buffered read and read more if necessary.
281     while (remaining) {
282         bufferedReadSize = m_readLeft < remaining ? m_readLeft : remaining;
283         if (bufferedReadSize) {
284             memcpy(userReadBuf + (totalReadSize - remaining),
285                    m_readBuf + (m_read - m_readLeft),
286                    bufferedReadSize);
287             remaining -= bufferedReadSize;
288             m_readLeft -= bufferedReadSize;
289             continue;
290         }
291 
292         actual = speculativeRead(m_readBuf, kReadSize);
293 
294         if (actual == 0) {
295             ALOGD("%s: Failed reading from pipe: %d", __FUNCTION__,  errno);
296             return NULL;
297         }
298 
299         if (actual > 0) {
300             m_read = m_readLeft = actual;
301             continue;
302         }
303     }
304 
305     return userReadBuf;
306 }
307 
read(void * buf,size_t * inout_len)308 const unsigned char *AddressSpaceStream::read(void *buf, size_t *inout_len) {
309     unsigned char* dst = (unsigned char*)buf;
310     size_t wanted = *inout_len;
311     ssize_t actual = speculativeRead(dst, wanted);
312 
313     if (actual >= 0) {
314         *inout_len = actual;
315     } else {
316         return nullptr;
317     }
318 
319     return (const unsigned char*)dst;
320 }
321 
writeFully(const void * buf,size_t size)322 int AddressSpaceStream::writeFully(const void *buf, size_t size)
323 {
324     ensureConsumerFinishing();
325     ensureType3Finished();
326     ensureType1Finished();
327 
328     m_context.ring_config->transfer_size = size;
329     m_context.ring_config->transfer_mode = 3;
330 
331     size_t sent = 0;
332     size_t quarterRingSize = m_writeBufferSize / 4;
333     size_t chunkSize = size < quarterRingSize ? size : quarterRingSize;
334     const uint8_t* bufferBytes = (const uint8_t*)buf;
335 
336     while (sent < size) {
337         size_t remaining = size - sent;
338         size_t sendThisTime = remaining < chunkSize ? remaining : chunkSize;
339 
340         long sentChunks =
341             ring_buffer_view_write(
342                 m_context.to_host_large_xfer.ring,
343                 &m_context.to_host_large_xfer.view,
344                 bufferBytes + sent, sendThisTime, 1);
345 
346         if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
347             notifyAvailable();
348         }
349 
350         if (sentChunks == 0) {
351             ring_buffer_yield();
352         }
353 
354         sent += sentChunks * sendThisTime;
355 
356         if (isInError()) {
357             return -1;
358         }
359     }
360 
361     ensureType3Finished();
362     m_context.ring_config->transfer_mode = 1;
363     m_written += size;
364     return 0;
365 }
366 
commitBufferAndReadFully(size_t writeSize,void * userReadBufPtr,size_t totalReadSize)367 const unsigned char *AddressSpaceStream::commitBufferAndReadFully(
368     size_t writeSize, void *userReadBufPtr, size_t totalReadSize) {
369 
370     if (m_usingTmpBuf) {
371         writeFully(m_tmpBuf, writeSize);
372         m_usingTmpBuf = false;
373         m_tmpBufXferSize = 0;
374         return readFully(userReadBufPtr, totalReadSize);
375     } else {
376         commitBuffer(writeSize);
377         return readFully(userReadBufPtr, totalReadSize);
378     }
379 }
380 
isInError() const381 bool AddressSpaceStream::isInError() const {
382     return 1 == m_context.ring_config->in_error;
383 }
384 
speculativeRead(unsigned char * readBuffer,size_t trySize)385 ssize_t AddressSpaceStream::speculativeRead(unsigned char* readBuffer, size_t trySize) {
386     ensureConsumerFinishing();
387     ensureType3Finished();
388     ensureType1Finished();
389 
390     size_t actuallyRead = 0;
391     while (!actuallyRead) {
392         uint32_t readAvail =
393             ring_buffer_available_read(
394                 m_context.from_host_large_xfer.ring,
395                 &m_context.from_host_large_xfer.view);
396 
397         if (!readAvail) {
398             ring_buffer_yield();
399             continue;
400         }
401 
402         uint32_t toRead = readAvail > trySize ?  trySize : readAvail;
403 
404         long stepsRead = ring_buffer_view_read(
405             m_context.from_host_large_xfer.ring,
406             &m_context.from_host_large_xfer.view,
407             readBuffer, toRead, 1);
408 
409         actuallyRead += stepsRead * toRead;
410 
411         if (isInError()) {
412             return -1;
413         }
414     }
415 
416     return actuallyRead;
417 }
418 
notifyAvailable()419 void AddressSpaceStream::notifyAvailable() {
420     struct goldfish_address_space_ping request;
421     request.metadata = ASG_NOTIFY_AVAILABLE;
422     goldfish_address_space_ping(m_handle, &request);
423     ++m_notifs;
424 }
425 
getRelativeBufferPos(uint32_t pos)426 uint32_t AddressSpaceStream::getRelativeBufferPos(uint32_t pos) {
427     return pos & m_writeBufferMask;
428 }
429 
advanceWrite()430 void AddressSpaceStream::advanceWrite() {
431     m_writeStart += m_context.ring_config->flush_interval;
432 
433     if (m_writeStart == m_buf + m_context.ring_config->buffer_size) {
434         m_writeStart = m_buf;
435     }
436 }
437 
ensureConsumerFinishing()438 void AddressSpaceStream::ensureConsumerFinishing() {
439     uint32_t currAvailRead = ring_buffer_available_read(m_context.to_host, 0);
440 
441     while (currAvailRead) {
442         ring_buffer_yield();
443         uint32_t nextAvailRead = ring_buffer_available_read(m_context.to_host, 0);
444 
445         if (nextAvailRead != currAvailRead) {
446             break;
447         }
448 
449         if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
450             notifyAvailable();
451             break;
452         }
453     }
454 }
455 
ensureType1Finished()456 void AddressSpaceStream::ensureType1Finished() {
457     ensureConsumerFinishing();
458 
459     uint32_t currAvailRead =
460         ring_buffer_available_read(m_context.to_host, 0);
461 
462     while (currAvailRead) {
463         ring_buffer_yield();
464         currAvailRead = ring_buffer_available_read(m_context.to_host, 0);
465         if (isInError()) {
466             return;
467         }
468     }
469 }
470 
ensureType3Finished()471 void AddressSpaceStream::ensureType3Finished() {
472     uint32_t availReadLarge =
473         ring_buffer_available_read(
474             m_context.to_host_large_xfer.ring,
475             &m_context.to_host_large_xfer.view);
476     while (availReadLarge) {
477         ring_buffer_yield();
478         availReadLarge =
479             ring_buffer_available_read(
480                 m_context.to_host_large_xfer.ring,
481                 &m_context.to_host_large_xfer.view);
482         if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
483             notifyAvailable();
484         }
485         if (isInError()) {
486             return;
487         }
488     }
489 }
490 
type1Write(uint32_t bufferOffset,size_t size)491 int AddressSpaceStream::type1Write(uint32_t bufferOffset, size_t size) {
492     size_t sent = 0;
493     size_t sizeForRing = sizeof(struct asg_type1_xfer);
494 
495     struct asg_type1_xfer xfer = {
496         bufferOffset,
497         (uint32_t)size,
498     };
499 
500     uint8_t* writeBufferBytes = (uint8_t*)(&xfer);
501 
502     uint32_t maxOutstanding = 1;
503     uint32_t maxSteps = m_context.ring_config->buffer_size /
504             m_context.ring_config->flush_interval;
505 
506     if (maxSteps > 1) maxOutstanding = maxSteps >> 1;
507 
508     uint32_t ringAvailReadNow = ring_buffer_available_read(m_context.to_host, 0);
509 
510     while (ringAvailReadNow >= maxOutstanding) {
511         ensureConsumerFinishing();
512         ring_buffer_yield();
513         ringAvailReadNow = ring_buffer_available_read(m_context.to_host, 0);
514     }
515 
516     while (sent < sizeForRing) {
517 
518         long sentChunks = ring_buffer_write(
519             m_context.to_host,
520             writeBufferBytes + sent,
521             sizeForRing - sent, 1);
522 
523         if (*(m_context.host_state) != ASG_HOST_STATE_CAN_CONSUME) {
524             notifyAvailable();
525         }
526 
527         if (sentChunks == 0) {
528             ring_buffer_yield();
529         }
530 
531         sent += sentChunks * (sizeForRing - sent);
532 
533         if (isInError()) {
534             return -1;
535         }
536     }
537 
538     ensureConsumerFinishing();
539     m_written += size;
540 
541     float mb = (float)m_written / 1048576.0f;
542     if (mb > 100.0f) {
543         ALOGD("%s: %f mb in %d notifs. %f mb/notif\n", __func__,
544               mb, m_notifs, m_notifs ? mb / (float)m_notifs : 0.0f);
545         m_notifs = 0;
546         m_written = 0;
547     }
548 
549     return 0;
550 }
551