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