| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.mojo_base; |
| |
| import org.chromium.mojo.system.Core; |
| import org.chromium.mojo.system.SharedBufferHandle; |
| import org.chromium.mojo.system.impl.CoreImpl; |
| import org.chromium.mojo_base.mojom.BigBuffer; |
| import org.chromium.mojo_base.mojom.BigBufferSharedMemoryRegion; |
| |
| import java.nio.ByteBuffer; |
| |
| /** Static helper methods for working with the mojom BigBuffer type. */ |
| public final class BigBufferUtil { |
| public static final int MAX_INLINE_ARRAY_SIZE = 64 * 1024; |
| |
| /** |
| * A mapping to a BigBuffer. |
| * |
| * If it is backed by shared memory, this will be a direct mapping which must be closed and will |
| * be invalid thereafter. The simplest way to do this is by using try-with-resources. |
| */ |
| public static class Mapping implements AutoCloseable { |
| private final SharedBufferHandle mHandle; |
| private final ByteBuffer mBuffer; |
| |
| Mapping(SharedBufferHandle handle, ByteBuffer buffer) { |
| mHandle = handle; |
| mBuffer = buffer; |
| } |
| |
| public ByteBuffer getBuffer() { |
| return mBuffer; |
| } |
| |
| @Override |
| public void close() { |
| if (mHandle != null) { |
| mHandle.unmap(mBuffer); |
| } |
| } |
| } |
| |
| // Retrives a copy of the buffer's contents regardless of what type was backing it (i.e. array |
| // or shared memory). |
| public static byte[] getBytesFromBigBuffer(BigBuffer buffer) { |
| if (buffer.which() == BigBuffer.Tag.Bytes) { |
| return buffer.getBytes(); |
| } else { |
| BigBufferSharedMemoryRegion region = buffer.getSharedMemory(); |
| ByteBuffer byteBuffer = |
| region.bufferHandle.map(0, region.size, SharedBufferHandle.MapFlags.NONE); |
| byte[] bytes = new byte[region.size]; |
| byteBuffer.get(bytes); |
| region.bufferHandle.unmap(byteBuffer); |
| return bytes; |
| } |
| } |
| |
| // Opens a mapping to an existing buffer for direct reading, without a copy. |
| // This must be used with a try-with-resources so that close is called to prevent a leak. |
| // The direct buffer must not be used after close is called. |
| public static Mapping map(BigBuffer buffer) { |
| if (buffer.which() == BigBuffer.Tag.Bytes) { |
| return new Mapping(null, ByteBuffer.wrap(buffer.getBytes())); |
| } else { |
| BigBufferSharedMemoryRegion region = buffer.getSharedMemory(); |
| ByteBuffer byteBuffer = |
| region.bufferHandle.map(0, region.size, SharedBufferHandle.MapFlags.NONE); |
| return new Mapping(region.bufferHandle, byteBuffer); |
| } |
| } |
| |
| // Creates a new mojom.BigBuffer for IPC from a set of bytes. If the byte array is larger than |
| // MAX_INLINE_ARRAY_SIZE, shared memory will be used instead of an inline array. |
| public static BigBuffer createBigBufferFromBytes(byte[] bytes) { |
| BigBuffer buffer = new BigBuffer(); |
| if (bytes.length <= MAX_INLINE_ARRAY_SIZE) { |
| buffer.setBytes(bytes); |
| return buffer; |
| } |
| Core core = CoreImpl.getInstance(); |
| BigBufferSharedMemoryRegion region = new BigBufferSharedMemoryRegion(); |
| region.bufferHandle = |
| core.createSharedBuffer(new SharedBufferHandle.CreateOptions(), bytes.length); |
| region.size = bytes.length; |
| ByteBuffer mappedRegion = |
| region.bufferHandle.map(0, bytes.length, SharedBufferHandle.MapFlags.NONE); |
| mappedRegion.put(bytes); |
| region.bufferHandle.unmap(mappedRegion); |
| buffer.setSharedMemory(region); |
| return buffer; |
| } |
| } |