diff options
Diffstat (limited to 'mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java')
-rw-r--r-- | mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java b/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java new file mode 100644 index 0000000000..173f80180f --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/impl/CoreImpl.java @@ -0,0 +1,522 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.mojo.system.impl; + +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.MainDex; +import org.chromium.mojo.system.Core; +import org.chromium.mojo.system.Core.HandleSignalsState; +import org.chromium.mojo.system.DataPipe; +import org.chromium.mojo.system.DataPipe.ConsumerHandle; +import org.chromium.mojo.system.DataPipe.ProducerHandle; +import org.chromium.mojo.system.Handle; +import org.chromium.mojo.system.MessagePipeHandle; +import org.chromium.mojo.system.MojoException; +import org.chromium.mojo.system.MojoResult; +import org.chromium.mojo.system.Pair; +import org.chromium.mojo.system.ResultAnd; +import org.chromium.mojo.system.RunLoop; +import org.chromium.mojo.system.SharedBufferHandle; +import org.chromium.mojo.system.SharedBufferHandle.DuplicateOptions; +import org.chromium.mojo.system.SharedBufferHandle.MapFlags; +import org.chromium.mojo.system.UntypedHandle; +import org.chromium.mojo.system.Watcher; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +/** + * Implementation of {@link Core}. + */ +@JNINamespace("mojo::android") +@MainDex +public class CoreImpl implements Core { + /** + * Discard flag for the |MojoReadData| operation. + */ + private static final int MOJO_READ_DATA_FLAG_DISCARD = 1 << 1; + + /** + * the size of a handle, in bytes. + */ + private static final int HANDLE_SIZE = 4; + + /** + * the size of a flag, in bytes. + */ + private static final int FLAG_SIZE = 4; + + /** + * The mojo handle for an invalid handle. + */ + static final int INVALID_HANDLE = 0; + + private static class LazyHolder { private static final Core INSTANCE = new CoreImpl(); } + + /** + * The run loop for the current thread. + */ + private final ThreadLocal<BaseRunLoop> mCurrentRunLoop = new ThreadLocal<BaseRunLoop>(); + + /** + * The offset needed to get an aligned buffer. + */ + private final int mByteBufferOffset; + + /** + * @return the instance. + */ + public static Core getInstance() { + return LazyHolder.INSTANCE; + } + + private CoreImpl() { + // Fix for the ART runtime, before: + // https://android.googlesource.com/platform/libcore/+/fb6c80875a8a8d0a9628562f89c250b6a962e824%5E!/ + // This assumes consistent allocation. + mByteBufferOffset = nativeGetNativeBufferOffset(ByteBuffer.allocateDirect(8), 8); + } + + /** + * @see Core#getTimeTicksNow() + */ + @Override + public long getTimeTicksNow() { + return nativeGetTimeTicksNow(); + } + + /** + * @see Core#createMessagePipe(MessagePipeHandle.CreateOptions) + */ + @Override + public Pair<MessagePipeHandle, MessagePipeHandle> createMessagePipe( + MessagePipeHandle.CreateOptions options) { + ByteBuffer optionsBuffer = null; + if (options != null) { + optionsBuffer = allocateDirectBuffer(8); + optionsBuffer.putInt(0, 8); + optionsBuffer.putInt(4, options.getFlags().getFlags()); + } + ResultAnd<IntegerPair> result = nativeCreateMessagePipe(optionsBuffer); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return Pair.<MessagePipeHandle, MessagePipeHandle>create( + new MessagePipeHandleImpl(this, result.getValue().first), + new MessagePipeHandleImpl(this, result.getValue().second)); + } + + /** + * @see Core#createDataPipe(DataPipe.CreateOptions) + */ + @Override + public Pair<ProducerHandle, ConsumerHandle> createDataPipe(DataPipe.CreateOptions options) { + ByteBuffer optionsBuffer = null; + if (options != null) { + optionsBuffer = allocateDirectBuffer(16); + optionsBuffer.putInt(0, 16); + optionsBuffer.putInt(4, options.getFlags().getFlags()); + optionsBuffer.putInt(8, options.getElementNumBytes()); + optionsBuffer.putInt(12, options.getCapacityNumBytes()); + } + ResultAnd<IntegerPair> result = nativeCreateDataPipe(optionsBuffer); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return Pair.<ProducerHandle, ConsumerHandle>create( + new DataPipeProducerHandleImpl(this, result.getValue().first), + new DataPipeConsumerHandleImpl(this, result.getValue().second)); + } + + /** + * @see Core#createSharedBuffer(SharedBufferHandle.CreateOptions, long) + */ + @Override + public SharedBufferHandle createSharedBuffer( + SharedBufferHandle.CreateOptions options, long numBytes) { + ByteBuffer optionsBuffer = null; + if (options != null) { + optionsBuffer = allocateDirectBuffer(8); + optionsBuffer.putInt(0, 8); + optionsBuffer.putInt(4, options.getFlags().getFlags()); + } + ResultAnd<Integer> result = nativeCreateSharedBuffer(optionsBuffer, numBytes); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return new SharedBufferHandleImpl(this, result.getValue()); + } + + /** + * @see org.chromium.mojo.system.Core#acquireNativeHandle(int) + */ + @Override + public UntypedHandle acquireNativeHandle(int handle) { + return new UntypedHandleImpl(this, handle); + } + + /** + * @see Core#getWatcher() + */ + @Override + public Watcher getWatcher() { + return new WatcherImpl(); + } + + /** + * @see Core#createDefaultRunLoop() + */ + @Override + public RunLoop createDefaultRunLoop() { + if (mCurrentRunLoop.get() != null) { + throw new MojoException(MojoResult.FAILED_PRECONDITION); + } + BaseRunLoop runLoop = new BaseRunLoop(this); + mCurrentRunLoop.set(runLoop); + return runLoop; + } + + /** + * @see Core#getCurrentRunLoop() + */ + @Override + public RunLoop getCurrentRunLoop() { + return mCurrentRunLoop.get(); + } + + /** + * Remove the current run loop. + */ + void clearCurrentRunLoop() { + mCurrentRunLoop.remove(); + } + + int closeWithResult(int mojoHandle) { + return nativeClose(mojoHandle); + } + + void close(int mojoHandle) { + int mojoResult = nativeClose(mojoHandle); + if (mojoResult != MojoResult.OK) { + throw new MojoException(mojoResult); + } + } + + HandleSignalsState queryHandleSignalsState(int mojoHandle) { + ByteBuffer buffer = allocateDirectBuffer(8); + int result = nativeQueryHandleSignalsState(mojoHandle, buffer); + if (result != MojoResult.OK) throw new MojoException(result); + return new HandleSignalsState( + new HandleSignals(buffer.getInt(0)), new HandleSignals(buffer.getInt(4))); + } + + /** + * @see MessagePipeHandle#writeMessage(ByteBuffer, List, MessagePipeHandle.WriteFlags) + */ + void writeMessage(MessagePipeHandleImpl pipeHandle, ByteBuffer bytes, + List<? extends Handle> handles, MessagePipeHandle.WriteFlags flags) { + ByteBuffer handlesBuffer = null; + if (handles != null && !handles.isEmpty()) { + handlesBuffer = allocateDirectBuffer(handles.size() * HANDLE_SIZE); + for (Handle handle : handles) { + handlesBuffer.putInt(getMojoHandle(handle)); + } + handlesBuffer.position(0); + } + int mojoResult = nativeWriteMessage(pipeHandle.getMojoHandle(), bytes, + bytes == null ? 0 : bytes.limit(), handlesBuffer, flags.getFlags()); + if (mojoResult != MojoResult.OK) { + throw new MojoException(mojoResult); + } + // Success means the handles have been invalidated. + if (handles != null) { + for (Handle handle : handles) { + if (handle.isValid()) { + ((HandleBase) handle).invalidateHandle(); + } + } + } + } + + /** + * @see MessagePipeHandle#readMessage(ByteBuffer, int, MessagePipeHandle.ReadFlags) + */ + ResultAnd<MessagePipeHandle.ReadMessageResult> readMessage(MessagePipeHandleImpl handle, + ByteBuffer bytes, int maxNumberOfHandles, MessagePipeHandle.ReadFlags flags) { + ByteBuffer handlesBuffer = null; + if (maxNumberOfHandles > 0) { + handlesBuffer = allocateDirectBuffer(maxNumberOfHandles * HANDLE_SIZE); + } + ResultAnd<MessagePipeHandle.ReadMessageResult> result = + nativeReadMessage(handle.getMojoHandle(), bytes, handlesBuffer, flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK + && result.getMojoResult() != MojoResult.RESOURCE_EXHAUSTED + && result.getMojoResult() != MojoResult.SHOULD_WAIT) { + throw new MojoException(result.getMojoResult()); + } + + if (result.getMojoResult() == MojoResult.OK) { + MessagePipeHandle.ReadMessageResult readResult = result.getValue(); + if (bytes != null) { + bytes.position(0); + bytes.limit(readResult.getMessageSize()); + } + + List<UntypedHandle> handles = + new ArrayList<UntypedHandle>(readResult.getHandlesCount()); + for (int i = 0; i < readResult.getHandlesCount(); ++i) { + int mojoHandle = handlesBuffer.getInt(HANDLE_SIZE * i); + handles.add(new UntypedHandleImpl(this, mojoHandle)); + } + readResult.setHandles(handles); + } + return result; + } + + /** + * @see ConsumerHandle#discardData(int, DataPipe.ReadFlags) + */ + int discardData(DataPipeConsumerHandleImpl handle, int numBytes, DataPipe.ReadFlags flags) { + ResultAnd<Integer> result = nativeReadData(handle.getMojoHandle(), null, numBytes, + flags.getFlags() | MOJO_READ_DATA_FLAG_DISCARD); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return result.getValue(); + } + + /** + * @see ConsumerHandle#readData(ByteBuffer, DataPipe.ReadFlags) + */ + ResultAnd<Integer> readData( + DataPipeConsumerHandleImpl handle, ByteBuffer elements, DataPipe.ReadFlags flags) { + ResultAnd<Integer> result = nativeReadData(handle.getMojoHandle(), elements, + elements == null ? 0 : elements.capacity(), flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK + && result.getMojoResult() != MojoResult.SHOULD_WAIT) { + throw new MojoException(result.getMojoResult()); + } + if (result.getMojoResult() == MojoResult.OK) { + if (elements != null) { + elements.limit(result.getValue()); + } + } + return result; + } + + /** + * @see ConsumerHandle#beginReadData(int, DataPipe.ReadFlags) + */ + ByteBuffer beginReadData( + DataPipeConsumerHandleImpl handle, int numBytes, DataPipe.ReadFlags flags) { + ResultAnd<ByteBuffer> result = + nativeBeginReadData(handle.getMojoHandle(), numBytes, flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return result.getValue().asReadOnlyBuffer(); + } + + /** + * @see ConsumerHandle#endReadData(int) + */ + void endReadData(DataPipeConsumerHandleImpl handle, int numBytesRead) { + int result = nativeEndReadData(handle.getMojoHandle(), numBytesRead); + if (result != MojoResult.OK) { + throw new MojoException(result); + } + } + + /** + * @see ProducerHandle#writeData(ByteBuffer, DataPipe.WriteFlags) + */ + ResultAnd<Integer> writeData( + DataPipeProducerHandleImpl handle, ByteBuffer elements, DataPipe.WriteFlags flags) { + return nativeWriteData( + handle.getMojoHandle(), elements, elements.limit(), flags.getFlags()); + } + + /** + * @see ProducerHandle#beginWriteData(int, DataPipe.WriteFlags) + */ + ByteBuffer beginWriteData( + DataPipeProducerHandleImpl handle, int numBytes, DataPipe.WriteFlags flags) { + ResultAnd<ByteBuffer> result = + nativeBeginWriteData(handle.getMojoHandle(), numBytes, flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return result.getValue(); + } + + /** + * @see ProducerHandle#endWriteData(int) + */ + void endWriteData(DataPipeProducerHandleImpl handle, int numBytesWritten) { + int result = nativeEndWriteData(handle.getMojoHandle(), numBytesWritten); + if (result != MojoResult.OK) { + throw new MojoException(result); + } + } + + /** + * @see SharedBufferHandle#duplicate(DuplicateOptions) + */ + SharedBufferHandle duplicate(SharedBufferHandleImpl handle, DuplicateOptions options) { + ByteBuffer optionsBuffer = null; + if (options != null) { + optionsBuffer = allocateDirectBuffer(8); + optionsBuffer.putInt(0, 8); + optionsBuffer.putInt(4, options.getFlags().getFlags()); + } + ResultAnd<Integer> result = nativeDuplicate(handle.getMojoHandle(), optionsBuffer); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return new SharedBufferHandleImpl(this, result.getValue()); + } + + /** + * @see SharedBufferHandle#map(long, long, MapFlags) + */ + ByteBuffer map(SharedBufferHandleImpl handle, long offset, long numBytes, MapFlags flags) { + ResultAnd<ByteBuffer> result = + nativeMap(handle.getMojoHandle(), offset, numBytes, flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return result.getValue(); + } + + /** + * @see SharedBufferHandle#unmap(ByteBuffer) + */ + void unmap(ByteBuffer buffer) { + int result = nativeUnmap(buffer); + if (result != MojoResult.OK) { + throw new MojoException(result); + } + } + + /** + * @return the mojo handle associated to the given handle, considering invalid handles. + */ + private int getMojoHandle(Handle handle) { + if (handle.isValid()) { + return ((HandleBase) handle).getMojoHandle(); + } + return 0; + } + + private static boolean isUnrecoverableError(int code) { + switch (code) { + case MojoResult.OK: + case MojoResult.DEADLINE_EXCEEDED: + case MojoResult.CANCELLED: + case MojoResult.FAILED_PRECONDITION: + return false; + default: + return true; + } + } + + private static int filterMojoResultForWait(int code) { + if (isUnrecoverableError(code)) { + throw new MojoException(code); + } + return code; + } + + private ByteBuffer allocateDirectBuffer(int capacity) { + ByteBuffer buffer = ByteBuffer.allocateDirect(capacity + mByteBufferOffset); + if (mByteBufferOffset != 0) { + buffer.position(mByteBufferOffset); + buffer = buffer.slice(); + } + return buffer.order(ByteOrder.nativeOrder()); + } + + @CalledByNative + private static ResultAnd<ByteBuffer> newResultAndBuffer(int mojoResult, ByteBuffer buffer) { + return new ResultAnd<>(mojoResult, buffer); + } + + /** + * Trivial alias for Pair<Integer, Integer>. This is needed because our jni generator is unable + * to handle class that contains space. + */ + private static final class IntegerPair extends Pair<Integer, Integer> { + public IntegerPair(Integer first, Integer second) { + super(first, second); + } + } + + @CalledByNative + private static ResultAnd<MessagePipeHandle.ReadMessageResult> newReadMessageResult( + int mojoResult, int messageSize, int handlesCount) { + MessagePipeHandle.ReadMessageResult result = new MessagePipeHandle.ReadMessageResult(); + result.setMessageSize(messageSize); + result.setHandlesCount(handlesCount); + return new ResultAnd<>(mojoResult, result); + } + + @CalledByNative + private static ResultAnd<Integer> newResultAndInteger(int mojoResult, int numBytesRead) { + return new ResultAnd<>(mojoResult, numBytesRead); + } + + @CalledByNative + private static ResultAnd<IntegerPair> newNativeCreationResult( + int mojoResult, int mojoHandle1, int mojoHandle2) { + return new ResultAnd<>(mojoResult, new IntegerPair(mojoHandle1, mojoHandle2)); + } + + private native long nativeGetTimeTicksNow(); + + private native ResultAnd<IntegerPair> nativeCreateMessagePipe(ByteBuffer optionsBuffer); + + private native ResultAnd<IntegerPair> nativeCreateDataPipe(ByteBuffer optionsBuffer); + + private native ResultAnd<Integer> nativeCreateSharedBuffer( + ByteBuffer optionsBuffer, long numBytes); + + private native int nativeClose(int mojoHandle); + + private native int nativeQueryHandleSignalsState(int mojoHandle, ByteBuffer signalsStateBuffer); + + private native int nativeWriteMessage( + int mojoHandle, ByteBuffer bytes, int numBytes, ByteBuffer handlesBuffer, int flags); + + private native ResultAnd<MessagePipeHandle.ReadMessageResult> nativeReadMessage( + int mojoHandle, ByteBuffer bytes, ByteBuffer handlesBuffer, int flags); + + private native ResultAnd<Integer> nativeReadData( + int mojoHandle, ByteBuffer elements, int elementsSize, int flags); + + private native ResultAnd<ByteBuffer> nativeBeginReadData( + int mojoHandle, int numBytes, int flags); + + private native int nativeEndReadData(int mojoHandle, int numBytesRead); + + private native ResultAnd<Integer> nativeWriteData( + int mojoHandle, ByteBuffer elements, int limit, int flags); + + private native ResultAnd<ByteBuffer> nativeBeginWriteData( + int mojoHandle, int numBytes, int flags); + + private native int nativeEndWriteData(int mojoHandle, int numBytesWritten); + + private native ResultAnd<Integer> nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer); + + private native ResultAnd<ByteBuffer> nativeMap( + int mojoHandle, long offset, long numBytes, int flags); + + private native int nativeUnmap(ByteBuffer buffer); + + private native int nativeGetNativeBufferOffset(ByteBuffer buffer, int alignment); +} |