1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.mojo.system.impl;
7 import org.chromium.base.CalledByNative;
8 import org.chromium.base.JNINamespace;
9 import org.chromium.mojo.system.AsyncWaiter;
10 import org.chromium.mojo.system.Core;
11 import org.chromium.mojo.system.DataPipe;
12 import org.chromium.mojo.system.DataPipe.ConsumerHandle;
13 import org.chromium.mojo.system.DataPipe.ProducerHandle;
14 import org.chromium.mojo.system.Handle;
15 import org.chromium.mojo.system.MessagePipeHandle;
16 import org.chromium.mojo.system.MojoException;
17 import org.chromium.mojo.system.MojoResult;
18 import org.chromium.mojo.system.Pair;
19 import org.chromium.mojo.system.SharedBufferHandle;
20 import org.chromium.mojo.system.SharedBufferHandle.DuplicateOptions;
21 import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
22 import org.chromium.mojo.system.UntypedHandle;
24 import java.nio.ByteBuffer;
25 import java.nio.ByteOrder;
26 import java.util.ArrayList;
27 import java.util.List;
30 * Implementation of {@link Core}.
32 @JNINamespace("mojo::android")
33 public class CoreImpl implements Core, AsyncWaiter {
36 * Discard flag for the |MojoReadData| operation.
38 private static final int MOJO_READ_DATA_FLAG_DISCARD = 1 << 1;
41 * the size of a handle, in bytes.
43 private static final int HANDLE_SIZE = 4;
46 * the size of a flag, in bytes.
48 private static final int FLAG_SIZE = 4;
51 * The mojo handle for an invalid handle.
53 static final int INVALID_HANDLE = 0;
55 private static class LazyHolder {
56 private static final Core INSTANCE = new CoreImpl();
60 * @return the instance.
62 public static Core getInstance() {
63 return LazyHolder.INSTANCE;
71 * @see Core#getTimeTicksNow()
74 public long getTimeTicksNow() {
75 return nativeGetTimeTicksNow();
79 * @see Core#waitMany(List, long)
82 public WaitManyResult waitMany(List<Pair<Handle, HandleSignals>> handles, long deadline) {
83 // Allocate a direct buffer to allow native code not to reach back to java. Buffer will
84 // contain all mojo handles, followed by all flags values.
85 ByteBuffer buffer = allocateDirectBuffer(handles.size() * 8);
87 for (Pair<Handle, HandleSignals> handle : handles) {
88 buffer.putInt(HANDLE_SIZE * index, getMojoHandle(handle.first));
89 buffer.putInt(HANDLE_SIZE * handles.size() + FLAG_SIZE * index,
90 handle.second.getFlags());
93 int code = nativeWaitMany(buffer, deadline);
94 WaitManyResult result = new WaitManyResult();
95 // If result is greater than 0, result is the indexed of the available handle. To make sure
96 // it cannot be misinterpreted, set handleIndex to a negative number in case of error.
97 result.setHandleIndex(code);
98 result.setMojoResult(filterMojoResultForWait(code));
103 * @see Core#wait(Handle, HandleSignals, long)
106 public int wait(Handle handle, HandleSignals signals, long deadline) {
107 return filterMojoResultForWait(nativeWait(getMojoHandle(handle),
108 signals.getFlags(), deadline));
112 * @see Core#createMessagePipe(MessagePipeHandle.CreateOptions)
115 public Pair<MessagePipeHandle, MessagePipeHandle> createMessagePipe(
116 MessagePipeHandle.CreateOptions options) {
117 ByteBuffer optionsBuffer = null;
118 if (options != null) {
119 optionsBuffer = allocateDirectBuffer(8);
120 optionsBuffer.putInt(0, 8);
121 optionsBuffer.putInt(4, options.getFlags().getFlags());
123 NativeCreationResult result = nativeCreateMessagePipe(optionsBuffer);
124 if (result.getMojoResult() != MojoResult.OK) {
125 throw new MojoException(result.getMojoResult());
127 return Pair.<MessagePipeHandle, MessagePipeHandle> create(
128 new MessagePipeHandleImpl(this, result.getMojoHandle1()),
129 new MessagePipeHandleImpl(this, result.getMojoHandle2()));
133 * @see Core#createDataPipe(DataPipe.CreateOptions)
136 public Pair<ProducerHandle, ConsumerHandle> createDataPipe(DataPipe.CreateOptions options) {
137 ByteBuffer optionsBuffer = null;
138 if (options != null) {
139 optionsBuffer = allocateDirectBuffer(16);
140 optionsBuffer.putInt(0, 16);
141 optionsBuffer.putInt(4, options.getFlags().getFlags());
142 optionsBuffer.putInt(8, options.getElementNumBytes());
143 optionsBuffer.putInt(12, options.getCapacityNumBytes());
145 NativeCreationResult result = nativeCreateDataPipe(optionsBuffer);
146 if (result.getMojoResult() != MojoResult.OK) {
147 throw new MojoException(result.getMojoResult());
149 return Pair.<ProducerHandle, ConsumerHandle> create(
150 new DataPipeProducerHandleImpl(this, result.getMojoHandle1()),
151 new DataPipeConsumerHandleImpl(this, result.getMojoHandle2()));
155 * @see Core#createSharedBuffer(SharedBufferHandle.CreateOptions, long)
158 public SharedBufferHandle createSharedBuffer(
159 SharedBufferHandle.CreateOptions options, long numBytes) {
160 ByteBuffer optionsBuffer = null;
161 if (options != null) {
162 optionsBuffer = allocateDirectBuffer(8);
163 optionsBuffer.putInt(0, 8);
164 optionsBuffer.putInt(4, options.getFlags().getFlags());
166 NativeCreationResult result = nativeCreateSharedBuffer(optionsBuffer, numBytes);
167 if (result.getMojoResult() != MojoResult.OK) {
168 throw new MojoException(result.getMojoResult());
170 assert result.getMojoHandle2() == 0;
171 return new SharedBufferHandleImpl(this, result.getMojoHandle1());
175 * @see Core#getDefaultAsyncWaiter()
178 public AsyncWaiter getDefaultAsyncWaiter() {
183 * @see AsyncWaiter#asyncWait(Handle, Core.HandleSignals, long, Callback)
186 public Cancellable asyncWait(Handle handle, HandleSignals signals, long deadline,
188 return nativeAsyncWait(getMojoHandle(handle), signals.getFlags(), deadline, callback);
191 int closeWithResult(int mojoHandle) {
192 return nativeClose(mojoHandle);
195 void close(int mojoHandle) {
196 int mojoResult = nativeClose(mojoHandle);
197 if (mojoResult != MojoResult.OK) {
198 throw new MojoException(mojoResult);
203 * @see MessagePipeHandle#writeMessage(ByteBuffer, List, MessagePipeHandle.WriteFlags)
205 void writeMessage(MessagePipeHandleImpl pipeHandle, ByteBuffer bytes,
206 List<? extends Handle> handles, MessagePipeHandle.WriteFlags flags) {
207 ByteBuffer handlesBuffer = null;
208 if (handles != null && !handles.isEmpty()) {
209 handlesBuffer = allocateDirectBuffer(handles.size() * HANDLE_SIZE);
210 for (Handle handle : handles) {
211 handlesBuffer.putInt(getMojoHandle(handle));
213 handlesBuffer.position(0);
215 int mojoResult = nativeWriteMessage(pipeHandle.getMojoHandle(), bytes,
216 bytes == null ? 0 : bytes.limit(), handlesBuffer,
218 if (mojoResult != MojoResult.OK) {
219 throw new MojoException(mojoResult);
221 // Success means the handles have been invalidated.
222 if (handles != null) {
223 for (Handle handle : handles) {
224 if (handle.isValid()) {
225 ((HandleBase) handle).invalidateHandle();
232 * @see MessagePipeHandle#readMessage(ByteBuffer, int, MessagePipeHandle.ReadFlags)
234 MessagePipeHandle.ReadMessageResult readMessage(MessagePipeHandleImpl handle,
235 ByteBuffer bytes, int maxNumberOfHandles,
236 MessagePipeHandle.ReadFlags flags) {
237 ByteBuffer handlesBuffer = null;
238 if (maxNumberOfHandles > 0) {
239 handlesBuffer = allocateDirectBuffer(maxNumberOfHandles * HANDLE_SIZE);
241 MessagePipeHandle.ReadMessageResult result = nativeReadMessage(
242 handle.getMojoHandle(), bytes, handlesBuffer, flags.getFlags());
243 if (result.getMojoResult() != MojoResult.OK &&
244 result.getMojoResult() != MojoResult.RESOURCE_EXHAUSTED &&
245 result.getMojoResult() != MojoResult.SHOULD_WAIT) {
246 throw new MojoException(result.getMojoResult());
249 if (result.getMojoResult() == MojoResult.OK) {
252 bytes.limit(result.getMessageSize());
255 List<UntypedHandle> handles = new ArrayList<UntypedHandle>(
256 result.getHandlesCount());
257 for (int i = 0; i < result.getHandlesCount(); ++i) {
258 int mojoHandle = handlesBuffer.getInt(HANDLE_SIZE * i);
259 handles.add(new UntypedHandleImpl(this, mojoHandle));
261 result.setHandles(handles);
267 * @see ConsumerHandle#discardData(int, DataPipe.ReadFlags)
269 int discardData(DataPipeConsumerHandleImpl handle, int numBytes,
270 DataPipe.ReadFlags flags) {
271 int result = nativeReadData(handle.getMojoHandle(), null, numBytes,
272 flags.getFlags() | MOJO_READ_DATA_FLAG_DISCARD);
274 throw new MojoException(result);
280 * @see ConsumerHandle#readData(ByteBuffer, DataPipe.ReadFlags)
282 int readData(DataPipeConsumerHandleImpl handle, ByteBuffer elements,
283 DataPipe.ReadFlags flags) {
284 int result = nativeReadData(handle.getMojoHandle(), elements,
285 elements == null ? 0 : elements.capacity(),
288 throw new MojoException(result);
290 if (elements != null) {
291 elements.limit(result);
297 * @see ConsumerHandle#beginReadData(int, DataPipe.ReadFlags)
299 ByteBuffer beginReadData(DataPipeConsumerHandleImpl handle,
300 int numBytes, DataPipe.ReadFlags flags) {
301 NativeCodeAndBufferResult result = nativeBeginReadData(
302 handle.getMojoHandle(),
305 if (result.getMojoResult() != MojoResult.OK) {
306 throw new MojoException(result.getMojoResult());
308 return result.getBuffer().asReadOnlyBuffer();
312 * @see ConsumerHandle#endReadData(int)
314 void endReadData(DataPipeConsumerHandleImpl handle,
316 int result = nativeEndReadData(handle.getMojoHandle(), numBytesRead);
317 if (result != MojoResult.OK) {
318 throw new MojoException(result);
323 * @see ProducerHandle#writeData(ByteBuffer, DataPipe.WriteFlags)
325 int writeData(DataPipeProducerHandleImpl handle, ByteBuffer elements,
326 DataPipe.WriteFlags flags) {
327 return nativeWriteData(handle.getMojoHandle(), elements, elements.limit(),
332 * @see ProducerHandle#beginWriteData(int, DataPipe.WriteFlags)
334 ByteBuffer beginWriteData(DataPipeProducerHandleImpl handle,
335 int numBytes, DataPipe.WriteFlags flags) {
336 NativeCodeAndBufferResult result = nativeBeginWriteData(
337 handle.getMojoHandle(),
340 if (result.getMojoResult() != MojoResult.OK) {
341 throw new MojoException(result.getMojoResult());
343 return result.getBuffer();
347 * @see ProducerHandle#endWriteData(int)
349 void endWriteData(DataPipeProducerHandleImpl handle,
350 int numBytesWritten) {
351 int result = nativeEndWriteData(handle.getMojoHandle(), numBytesWritten);
352 if (result != MojoResult.OK) {
353 throw new MojoException(result);
358 * @see SharedBufferHandle#duplicate(DuplicateOptions)
360 SharedBufferHandle duplicate(SharedBufferHandleImpl handle,
361 DuplicateOptions options) {
362 ByteBuffer optionsBuffer = null;
363 if (options != null) {
364 optionsBuffer = allocateDirectBuffer(8);
365 optionsBuffer.putInt(0, 8);
366 optionsBuffer.putInt(4, options.getFlags().getFlags());
368 NativeCreationResult result = nativeDuplicate(handle.getMojoHandle(),
370 if (result.getMojoResult() != MojoResult.OK) {
371 throw new MojoException(result.getMojoResult());
373 assert result.getMojoHandle2() == 0;
374 return new SharedBufferHandleImpl(this, result.getMojoHandle1());
378 * @see SharedBufferHandle#map(long, long, MapFlags)
380 ByteBuffer map(SharedBufferHandleImpl handle, long offset, long numBytes,
382 NativeCodeAndBufferResult result = nativeMap(handle.getMojoHandle(), offset, numBytes,
384 if (result.getMojoResult() != MojoResult.OK) {
385 throw new MojoException(result.getMojoResult());
387 return result.getBuffer();
391 * @see SharedBufferHandle#unmap(ByteBuffer)
393 void unmap(ByteBuffer buffer) {
394 int result = nativeUnmap(buffer);
395 if (result != MojoResult.OK) {
396 throw new MojoException(result);
401 * @return the mojo handle associated to the given handle, considering invalid handles.
403 private int getMojoHandle(Handle handle) {
404 if (handle.isValid()) {
405 return ((HandleBase) handle).getMojoHandle();
410 private static boolean isUnrecoverableError(int code) {
413 case MojoResult.DEADLINE_EXCEEDED:
414 case MojoResult.CANCELLED:
415 case MojoResult.FAILED_PRECONDITION:
422 private static int filterMojoResult(int code) {
424 return MojoResult.OK;
429 private static int filterMojoResultForWait(int code) {
430 int finalCode = filterMojoResult(code);
431 if (isUnrecoverableError(finalCode)) {
432 throw new MojoException(finalCode);
437 private static ByteBuffer allocateDirectBuffer(int capacity) {
438 ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
439 buffer.order(ByteOrder.nativeOrder());
443 private static class NativeCodeAndBufferResult {
444 private int mMojoResult;
445 private ByteBuffer mBuffer;
448 * @return the mojoResult
450 public int getMojoResult() {
455 * @param mojoResult the mojoResult to set
457 public void setMojoResult(int mojoResult) {
458 mMojoResult = mojoResult;
464 public ByteBuffer getBuffer() {
469 * @param buffer the buffer to set
471 public void setBuffer(ByteBuffer buffer) {
478 * Implementation of {@link org.chromium.mojo.system.AsyncWaiter.Cancellable}.
480 private class AsyncWaiterCancellableImpl implements AsyncWaiter.Cancellable {
482 private final long mId;
483 private final long mDataPtr;
484 private boolean mActive = true;
486 private AsyncWaiterCancellableImpl(long id, long dataPtr) {
488 this.mDataPtr = dataPtr;
492 * @see org.chromium.mojo.system.AsyncWaiter.Cancellable#cancel()
495 public void cancel() {
498 nativeCancelAsyncWait(mId, mDataPtr);
502 private boolean isActive() {
506 private void deactivate() {
512 private AsyncWaiterCancellableImpl newAsyncWaiterCancellableImpl(long id, long dataPtr) {
513 return new AsyncWaiterCancellableImpl(id, dataPtr);
517 private void onAsyncWaitResult(int mojoResult,
518 AsyncWaiter.Callback callback,
519 AsyncWaiterCancellableImpl cancellable) {
520 if (!cancellable.isActive()) {
521 // If cancellable is not active, the user cancelled the wait.
524 cancellable.deactivate();
525 int finalCode = filterMojoResult(mojoResult);
526 if (isUnrecoverableError(finalCode)) {
527 callback.onError(new MojoException(finalCode));
530 callback.onResult(finalCode);
534 private static NativeCodeAndBufferResult newNativeCodeAndBufferResult(int mojoResult,
536 NativeCodeAndBufferResult result = new NativeCodeAndBufferResult();
537 result.setMojoResult(mojoResult);
538 result.setBuffer(buffer);
543 private static MessagePipeHandle.ReadMessageResult newReadMessageResult(int mojoResult,
546 MessagePipeHandle.ReadMessageResult result = new MessagePipeHandle.ReadMessageResult();
547 if (mojoResult >= 0) {
548 result.setMojoResult(MojoResult.OK);
550 result.setMojoResult(mojoResult);
552 result.setMessageSize(messageSize);
553 result.setHandlesCount(handlesCount);
557 private static class NativeCreationResult {
558 private int mMojoResult;
559 private int mMojoHandle1;
560 private int mMojoHandle2;
563 * @return the mojoResult
565 public int getMojoResult() {
570 * @param mojoResult the mojoResult to set
572 public void setMojoResult(int mojoResult) {
573 mMojoResult = mojoResult;
577 * @return the mojoHandle1
579 public int getMojoHandle1() {
584 * @param mojoHandle1 the mojoHandle1 to set
586 public void setMojoHandle1(int mojoHandle1) {
587 mMojoHandle1 = mojoHandle1;
591 * @return the mojoHandle2
593 public int getMojoHandle2() {
598 * @param mojoHandle2 the mojoHandle2 to set
600 public void setMojoHandle2(int mojoHandle2) {
601 mMojoHandle2 = mojoHandle2;
606 private static NativeCreationResult newNativeCreationResult(int mojoResult,
607 int mojoHandle1, int mojoHandle2) {
608 NativeCreationResult result = new NativeCreationResult();
609 result.setMojoResult(mojoResult);
610 result.setMojoHandle1(mojoHandle1);
611 result.setMojoHandle2(mojoHandle2);
615 private native void nativeConstructor();
617 private native long nativeGetTimeTicksNow();
619 private native int nativeWaitMany(ByteBuffer buffer, long deadline);
621 private native NativeCreationResult nativeCreateMessagePipe(ByteBuffer optionsBuffer);
623 private native NativeCreationResult nativeCreateDataPipe(ByteBuffer optionsBuffer);
625 private native NativeCreationResult nativeCreateSharedBuffer(ByteBuffer optionsBuffer,
628 private native int nativeClose(int mojoHandle);
630 private native int nativeWait(int mojoHandle, int signals, long deadline);
632 private native int nativeWriteMessage(int mojoHandle, ByteBuffer bytes, int numBytes,
633 ByteBuffer handlesBuffer, int flags);
635 private native MessagePipeHandle.ReadMessageResult nativeReadMessage(int mojoHandle,
637 ByteBuffer handlesBuffer,
640 private native int nativeReadData(int mojoHandle, ByteBuffer elements, int elementsSize,
643 private native NativeCodeAndBufferResult nativeBeginReadData(int mojoHandle, int numBytes,
646 private native int nativeEndReadData(int mojoHandle, int numBytesRead);
648 private native int nativeWriteData(int mojoHandle, ByteBuffer elements, int limit, int flags);
650 private native NativeCodeAndBufferResult nativeBeginWriteData(int mojoHandle, int numBytes,
653 private native int nativeEndWriteData(int mojoHandle, int numBytesWritten);
655 private native NativeCreationResult nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer);
657 private native NativeCodeAndBufferResult nativeMap(int mojoHandle, long offset, long numBytes,
660 private native int nativeUnmap(ByteBuffer buffer);
662 private native AsyncWaiterCancellableImpl nativeAsyncWait(int mojoHandle, int signals,
663 long deadline, AsyncWaiter.Callback callback);
665 private native void nativeCancelAsyncWait(long mId, long dataPtr);