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;
70 * @see Core#getTimeTicksNow()
73 public long getTimeTicksNow() {
74 return nativeGetTimeTicksNow();
78 * @see Core#waitMany(List, long)
81 public WaitManyResult waitMany(List<Pair<Handle, HandleSignals>> handles, long deadline) {
82 // Allocate a direct buffer to allow native code not to reach back to java. Buffer will
83 // contain all mojo handles, followed by all flags values.
84 ByteBuffer buffer = allocateDirectBuffer(handles.size() * 8);
86 for (Pair<Handle, HandleSignals> handle : handles) {
87 buffer.putInt(HANDLE_SIZE * index, getMojoHandle(handle.first));
88 buffer.putInt(HANDLE_SIZE * handles.size() + FLAG_SIZE * index,
89 handle.second.getFlags());
92 int code = nativeWaitMany(buffer, deadline);
93 WaitManyResult result = new WaitManyResult();
94 // If result is greater than 0, result is the indexed of the available handle. To make sure
95 // it cannot be misinterpreted, set handleIndex to a negative number in case of error.
96 result.setHandleIndex(code);
97 result.setMojoResult(filterMojoResultForWait(code));
102 * @see Core#wait(Handle, HandleSignals, long)
105 public int wait(Handle handle, HandleSignals signals, long deadline) {
106 return filterMojoResultForWait(nativeWait(getMojoHandle(handle),
107 signals.getFlags(), deadline));
111 * @see Core#createMessagePipe(MessagePipeHandle.CreateOptions)
114 public Pair<MessagePipeHandle, MessagePipeHandle> createMessagePipe(
115 MessagePipeHandle.CreateOptions options) {
116 ByteBuffer optionsBuffer = null;
117 if (options != null) {
118 optionsBuffer = allocateDirectBuffer(8);
119 optionsBuffer.putInt(0, 8);
120 optionsBuffer.putInt(4, options.getFlags().getFlags());
122 NativeCreationResult result = nativeCreateMessagePipe(optionsBuffer);
123 if (result.getMojoResult() != MojoResult.OK) {
124 throw new MojoException(result.getMojoResult());
126 return Pair.<MessagePipeHandle, MessagePipeHandle> create(
127 new MessagePipeHandleImpl(this, result.getMojoHandle1()),
128 new MessagePipeHandleImpl(this, result.getMojoHandle2()));
132 * @see Core#createDataPipe(DataPipe.CreateOptions)
135 public Pair<ProducerHandle, ConsumerHandle> createDataPipe(DataPipe.CreateOptions options) {
136 ByteBuffer optionsBuffer = null;
137 if (options != null) {
138 optionsBuffer = allocateDirectBuffer(16);
139 optionsBuffer.putInt(0, 16);
140 optionsBuffer.putInt(4, options.getFlags().getFlags());
141 optionsBuffer.putInt(8, options.getElementNumBytes());
142 optionsBuffer.putInt(12, options.getCapacityNumBytes());
144 NativeCreationResult result = nativeCreateDataPipe(optionsBuffer);
145 if (result.getMojoResult() != MojoResult.OK) {
146 throw new MojoException(result.getMojoResult());
148 return Pair.<ProducerHandle, ConsumerHandle> create(
149 new DataPipeProducerHandleImpl(this, result.getMojoHandle1()),
150 new DataPipeConsumerHandleImpl(this, result.getMojoHandle2()));
154 * @see Core#createSharedBuffer(SharedBufferHandle.CreateOptions, long)
157 public SharedBufferHandle createSharedBuffer(
158 SharedBufferHandle.CreateOptions options, long numBytes) {
159 ByteBuffer optionsBuffer = null;
160 if (options != null) {
161 optionsBuffer = allocateDirectBuffer(8);
162 optionsBuffer.putInt(0, 8);
163 optionsBuffer.putInt(4, options.getFlags().getFlags());
165 NativeCreationResult result = nativeCreateSharedBuffer(optionsBuffer, numBytes);
166 if (result.getMojoResult() != MojoResult.OK) {
167 throw new MojoException(result.getMojoResult());
169 assert result.getMojoHandle2() == 0;
170 return new SharedBufferHandleImpl(this, result.getMojoHandle1());
174 * @see org.chromium.mojo.system.Core#acquireNativeHandle(int)
177 public UntypedHandle acquireNativeHandle(int handle) {
178 return new UntypedHandleImpl(this, handle);
182 * @see Core#getDefaultAsyncWaiter()
185 public AsyncWaiter getDefaultAsyncWaiter() {
190 * @see AsyncWaiter#asyncWait(Handle, Core.HandleSignals, long, Callback)
193 public Cancellable asyncWait(Handle handle, HandleSignals signals, long deadline,
195 return nativeAsyncWait(getMojoHandle(handle), signals.getFlags(), deadline, callback);
198 int closeWithResult(int mojoHandle) {
199 return nativeClose(mojoHandle);
202 void close(int mojoHandle) {
203 int mojoResult = nativeClose(mojoHandle);
204 if (mojoResult != MojoResult.OK) {
205 throw new MojoException(mojoResult);
210 * @see MessagePipeHandle#writeMessage(ByteBuffer, List, MessagePipeHandle.WriteFlags)
212 void writeMessage(MessagePipeHandleImpl pipeHandle, ByteBuffer bytes,
213 List<? extends Handle> handles, MessagePipeHandle.WriteFlags flags) {
214 ByteBuffer handlesBuffer = null;
215 if (handles != null && !handles.isEmpty()) {
216 handlesBuffer = allocateDirectBuffer(handles.size() * HANDLE_SIZE);
217 for (Handle handle : handles) {
218 handlesBuffer.putInt(getMojoHandle(handle));
220 handlesBuffer.position(0);
222 int mojoResult = nativeWriteMessage(pipeHandle.getMojoHandle(), bytes,
223 bytes == null ? 0 : bytes.limit(), handlesBuffer,
225 if (mojoResult != MojoResult.OK) {
226 throw new MojoException(mojoResult);
228 // Success means the handles have been invalidated.
229 if (handles != null) {
230 for (Handle handle : handles) {
231 if (handle.isValid()) {
232 ((HandleBase) handle).invalidateHandle();
239 * @see MessagePipeHandle#readMessage(ByteBuffer, int, MessagePipeHandle.ReadFlags)
241 MessagePipeHandle.ReadMessageResult readMessage(MessagePipeHandleImpl handle,
242 ByteBuffer bytes, int maxNumberOfHandles,
243 MessagePipeHandle.ReadFlags flags) {
244 ByteBuffer handlesBuffer = null;
245 if (maxNumberOfHandles > 0) {
246 handlesBuffer = allocateDirectBuffer(maxNumberOfHandles * HANDLE_SIZE);
248 MessagePipeHandle.ReadMessageResult result = nativeReadMessage(
249 handle.getMojoHandle(), bytes, handlesBuffer, flags.getFlags());
250 if (result.getMojoResult() != MojoResult.OK &&
251 result.getMojoResult() != MojoResult.RESOURCE_EXHAUSTED &&
252 result.getMojoResult() != MojoResult.SHOULD_WAIT) {
253 throw new MojoException(result.getMojoResult());
256 if (result.getMojoResult() == MojoResult.OK) {
259 bytes.limit(result.getMessageSize());
262 List<UntypedHandle> handles = new ArrayList<UntypedHandle>(
263 result.getHandlesCount());
264 for (int i = 0; i < result.getHandlesCount(); ++i) {
265 int mojoHandle = handlesBuffer.getInt(HANDLE_SIZE * i);
266 handles.add(new UntypedHandleImpl(this, mojoHandle));
268 result.setHandles(handles);
274 * @see ConsumerHandle#discardData(int, DataPipe.ReadFlags)
276 int discardData(DataPipeConsumerHandleImpl handle, int numBytes,
277 DataPipe.ReadFlags flags) {
278 int result = nativeReadData(handle.getMojoHandle(), null, numBytes,
279 flags.getFlags() | MOJO_READ_DATA_FLAG_DISCARD);
281 throw new MojoException(result);
287 * @see ConsumerHandle#readData(ByteBuffer, DataPipe.ReadFlags)
289 int readData(DataPipeConsumerHandleImpl handle, ByteBuffer elements,
290 DataPipe.ReadFlags flags) {
291 int result = nativeReadData(handle.getMojoHandle(), elements,
292 elements == null ? 0 : elements.capacity(),
295 throw new MojoException(result);
297 if (elements != null) {
298 elements.limit(result);
304 * @see ConsumerHandle#beginReadData(int, DataPipe.ReadFlags)
306 ByteBuffer beginReadData(DataPipeConsumerHandleImpl handle,
307 int numBytes, DataPipe.ReadFlags flags) {
308 NativeCodeAndBufferResult result = nativeBeginReadData(
309 handle.getMojoHandle(),
312 if (result.getMojoResult() != MojoResult.OK) {
313 throw new MojoException(result.getMojoResult());
315 return result.getBuffer().asReadOnlyBuffer();
319 * @see ConsumerHandle#endReadData(int)
321 void endReadData(DataPipeConsumerHandleImpl handle,
323 int result = nativeEndReadData(handle.getMojoHandle(), numBytesRead);
324 if (result != MojoResult.OK) {
325 throw new MojoException(result);
330 * @see ProducerHandle#writeData(ByteBuffer, DataPipe.WriteFlags)
332 int writeData(DataPipeProducerHandleImpl handle, ByteBuffer elements,
333 DataPipe.WriteFlags flags) {
334 return nativeWriteData(handle.getMojoHandle(), elements, elements.limit(),
339 * @see ProducerHandle#beginWriteData(int, DataPipe.WriteFlags)
341 ByteBuffer beginWriteData(DataPipeProducerHandleImpl handle,
342 int numBytes, DataPipe.WriteFlags flags) {
343 NativeCodeAndBufferResult result = nativeBeginWriteData(
344 handle.getMojoHandle(),
347 if (result.getMojoResult() != MojoResult.OK) {
348 throw new MojoException(result.getMojoResult());
350 return result.getBuffer();
354 * @see ProducerHandle#endWriteData(int)
356 void endWriteData(DataPipeProducerHandleImpl handle,
357 int numBytesWritten) {
358 int result = nativeEndWriteData(handle.getMojoHandle(), numBytesWritten);
359 if (result != MojoResult.OK) {
360 throw new MojoException(result);
365 * @see SharedBufferHandle#duplicate(DuplicateOptions)
367 SharedBufferHandle duplicate(SharedBufferHandleImpl handle,
368 DuplicateOptions options) {
369 ByteBuffer optionsBuffer = null;
370 if (options != null) {
371 optionsBuffer = allocateDirectBuffer(8);
372 optionsBuffer.putInt(0, 8);
373 optionsBuffer.putInt(4, options.getFlags().getFlags());
375 NativeCreationResult result = nativeDuplicate(handle.getMojoHandle(),
377 if (result.getMojoResult() != MojoResult.OK) {
378 throw new MojoException(result.getMojoResult());
380 assert result.getMojoHandle2() == 0;
381 return new SharedBufferHandleImpl(this, result.getMojoHandle1());
385 * @see SharedBufferHandle#map(long, long, MapFlags)
387 ByteBuffer map(SharedBufferHandleImpl handle, long offset, long numBytes,
389 NativeCodeAndBufferResult result = nativeMap(handle.getMojoHandle(), offset, numBytes,
391 if (result.getMojoResult() != MojoResult.OK) {
392 throw new MojoException(result.getMojoResult());
394 return result.getBuffer();
398 * @see SharedBufferHandle#unmap(ByteBuffer)
400 void unmap(ByteBuffer buffer) {
401 int result = nativeUnmap(buffer);
402 if (result != MojoResult.OK) {
403 throw new MojoException(result);
408 * @return the mojo handle associated to the given handle, considering invalid handles.
410 private int getMojoHandle(Handle handle) {
411 if (handle.isValid()) {
412 return ((HandleBase) handle).getMojoHandle();
417 private static boolean isUnrecoverableError(int code) {
420 case MojoResult.DEADLINE_EXCEEDED:
421 case MojoResult.CANCELLED:
422 case MojoResult.FAILED_PRECONDITION:
429 private static int filterMojoResult(int code) {
431 return MojoResult.OK;
436 private static int filterMojoResultForWait(int code) {
437 int finalCode = filterMojoResult(code);
438 if (isUnrecoverableError(finalCode)) {
439 throw new MojoException(finalCode);
444 private static ByteBuffer allocateDirectBuffer(int capacity) {
445 ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
446 buffer.order(ByteOrder.nativeOrder());
450 private static class NativeCodeAndBufferResult {
451 private int mMojoResult;
452 private ByteBuffer mBuffer;
455 * @return the mojoResult
457 public int getMojoResult() {
462 * @param mojoResult the mojoResult to set
464 public void setMojoResult(int mojoResult) {
465 mMojoResult = mojoResult;
471 public ByteBuffer getBuffer() {
476 * @param buffer the buffer to set
478 public void setBuffer(ByteBuffer buffer) {
485 * Implementation of {@link org.chromium.mojo.system.AsyncWaiter.Cancellable}.
487 private class AsyncWaiterCancellableImpl implements AsyncWaiter.Cancellable {
489 private final long mId;
490 private final long mDataPtr;
491 private boolean mActive = true;
493 private AsyncWaiterCancellableImpl(long id, long dataPtr) {
495 this.mDataPtr = dataPtr;
499 * @see org.chromium.mojo.system.AsyncWaiter.Cancellable#cancel()
502 public void cancel() {
505 nativeCancelAsyncWait(mId, mDataPtr);
509 private boolean isActive() {
513 private void deactivate() {
519 private AsyncWaiterCancellableImpl newAsyncWaiterCancellableImpl(long id, long dataPtr) {
520 return new AsyncWaiterCancellableImpl(id, dataPtr);
524 private void onAsyncWaitResult(int mojoResult,
525 AsyncWaiter.Callback callback,
526 AsyncWaiterCancellableImpl cancellable) {
527 if (!cancellable.isActive()) {
528 // If cancellable is not active, the user cancelled the wait.
531 cancellable.deactivate();
532 int finalCode = filterMojoResult(mojoResult);
533 if (isUnrecoverableError(finalCode)) {
534 callback.onError(new MojoException(finalCode));
537 callback.onResult(finalCode);
541 private static NativeCodeAndBufferResult newNativeCodeAndBufferResult(int mojoResult,
543 NativeCodeAndBufferResult result = new NativeCodeAndBufferResult();
544 result.setMojoResult(mojoResult);
545 result.setBuffer(buffer);
550 private static MessagePipeHandle.ReadMessageResult newReadMessageResult(int mojoResult,
553 MessagePipeHandle.ReadMessageResult result = new MessagePipeHandle.ReadMessageResult();
554 if (mojoResult >= 0) {
555 result.setMojoResult(MojoResult.OK);
557 result.setMojoResult(mojoResult);
559 result.setMessageSize(messageSize);
560 result.setHandlesCount(handlesCount);
564 private static class NativeCreationResult {
565 private int mMojoResult;
566 private int mMojoHandle1;
567 private int mMojoHandle2;
570 * @return the mojoResult
572 public int getMojoResult() {
577 * @param mojoResult the mojoResult to set
579 public void setMojoResult(int mojoResult) {
580 mMojoResult = mojoResult;
584 * @return the mojoHandle1
586 public int getMojoHandle1() {
591 * @param mojoHandle1 the mojoHandle1 to set
593 public void setMojoHandle1(int mojoHandle1) {
594 mMojoHandle1 = mojoHandle1;
598 * @return the mojoHandle2
600 public int getMojoHandle2() {
605 * @param mojoHandle2 the mojoHandle2 to set
607 public void setMojoHandle2(int mojoHandle2) {
608 mMojoHandle2 = mojoHandle2;
613 private static NativeCreationResult newNativeCreationResult(int mojoResult,
614 int mojoHandle1, int mojoHandle2) {
615 NativeCreationResult result = new NativeCreationResult();
616 result.setMojoResult(mojoResult);
617 result.setMojoHandle1(mojoHandle1);
618 result.setMojoHandle2(mojoHandle2);
622 private native long nativeGetTimeTicksNow();
624 private native int nativeWaitMany(ByteBuffer buffer, long deadline);
626 private native NativeCreationResult nativeCreateMessagePipe(ByteBuffer optionsBuffer);
628 private native NativeCreationResult nativeCreateDataPipe(ByteBuffer optionsBuffer);
630 private native NativeCreationResult nativeCreateSharedBuffer(ByteBuffer optionsBuffer,
633 private native int nativeClose(int mojoHandle);
635 private native int nativeWait(int mojoHandle, int signals, long deadline);
637 private native int nativeWriteMessage(int mojoHandle, ByteBuffer bytes, int numBytes,
638 ByteBuffer handlesBuffer, int flags);
640 private native MessagePipeHandle.ReadMessageResult nativeReadMessage(int mojoHandle,
642 ByteBuffer handlesBuffer,
645 private native int nativeReadData(int mojoHandle, ByteBuffer elements, int elementsSize,
648 private native NativeCodeAndBufferResult nativeBeginReadData(int mojoHandle, int numBytes,
651 private native int nativeEndReadData(int mojoHandle, int numBytesRead);
653 private native int nativeWriteData(int mojoHandle, ByteBuffer elements, int limit, int flags);
655 private native NativeCodeAndBufferResult nativeBeginWriteData(int mojoHandle, int numBytes,
658 private native int nativeEndWriteData(int mojoHandle, int numBytesWritten);
660 private native NativeCreationResult nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer);
662 private native NativeCodeAndBufferResult nativeMap(int mojoHandle, long offset, long numBytes,
665 private native int nativeUnmap(ByteBuffer buffer);
667 private native AsyncWaiterCancellableImpl nativeAsyncWait(int mojoHandle, int signals,
668 long deadline, AsyncWaiter.Callback callback);
670 private native void nativeCancelAsyncWait(long mId, long dataPtr);