Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / mojo / android / system / src / org / chromium / mojo / system / impl / CoreImpl.java
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.
4
5 package org.chromium.mojo.system.impl;
6
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;
23
24 import java.nio.ByteBuffer;
25 import java.nio.ByteOrder;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 /**
30  * Implementation of {@link Core}.
31  */
32 @JNINamespace("mojo::android")
33 public class CoreImpl implements Core, AsyncWaiter {
34
35     /**
36      * Discard flag for the |MojoReadData| operation.
37      */
38     private static final int MOJO_READ_DATA_FLAG_DISCARD = 1 << 1;
39
40     /**
41      * the size of a handle, in bytes.
42      */
43     private static final int HANDLE_SIZE = 4;
44
45     /**
46      * the size of a flag, in bytes.
47      */
48     private static final int FLAG_SIZE = 4;
49
50     /**
51      * The mojo handle for an invalid handle.
52      */
53     static final int INVALID_HANDLE = 0;
54
55     private static class LazyHolder {
56         private static final Core INSTANCE = new CoreImpl();
57     }
58
59     /**
60      * @return the instance.
61      */
62     public static Core getInstance() {
63         return LazyHolder.INSTANCE;
64     }
65
66     private CoreImpl() {
67     }
68
69     /**
70      * @see Core#getTimeTicksNow()
71      */
72     @Override
73     public long getTimeTicksNow() {
74         return nativeGetTimeTicksNow();
75     }
76
77     /**
78      * @see Core#waitMany(List, long)
79      */
80     @Override
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);
85         int index = 0;
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());
90             index++;
91         }
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));
98         return result;
99     }
100
101     /**
102      * @see Core#wait(Handle, HandleSignals, long)
103      */
104     @Override
105     public int wait(Handle handle, HandleSignals signals, long deadline) {
106         return filterMojoResultForWait(nativeWait(getMojoHandle(handle),
107                 signals.getFlags(), deadline));
108     }
109
110     /**
111      * @see Core#createMessagePipe(MessagePipeHandle.CreateOptions)
112      */
113     @Override
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());
121         }
122         NativeCreationResult result = nativeCreateMessagePipe(optionsBuffer);
123         if (result.getMojoResult() != MojoResult.OK) {
124             throw new MojoException(result.getMojoResult());
125         }
126         return Pair.<MessagePipeHandle, MessagePipeHandle> create(
127                 new MessagePipeHandleImpl(this, result.getMojoHandle1()),
128                 new MessagePipeHandleImpl(this, result.getMojoHandle2()));
129     }
130
131     /**
132      * @see Core#createDataPipe(DataPipe.CreateOptions)
133      */
134     @Override
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());
143         }
144         NativeCreationResult result = nativeCreateDataPipe(optionsBuffer);
145         if (result.getMojoResult() != MojoResult.OK) {
146             throw new MojoException(result.getMojoResult());
147         }
148         return Pair.<ProducerHandle, ConsumerHandle> create(
149                 new DataPipeProducerHandleImpl(this, result.getMojoHandle1()),
150                 new DataPipeConsumerHandleImpl(this, result.getMojoHandle2()));
151     }
152
153     /**
154      * @see Core#createSharedBuffer(SharedBufferHandle.CreateOptions, long)
155      */
156     @Override
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());
164         }
165         NativeCreationResult result = nativeCreateSharedBuffer(optionsBuffer, numBytes);
166         if (result.getMojoResult() != MojoResult.OK) {
167             throw new MojoException(result.getMojoResult());
168         }
169         assert result.getMojoHandle2() == 0;
170         return new SharedBufferHandleImpl(this, result.getMojoHandle1());
171     }
172
173     /**
174      * @see org.chromium.mojo.system.Core#acquireNativeHandle(int)
175      */
176     @Override
177     public UntypedHandle acquireNativeHandle(int handle) {
178         return new UntypedHandleImpl(this, handle);
179     }
180
181     /**
182      * @see Core#getDefaultAsyncWaiter()
183      */
184     @Override
185     public AsyncWaiter getDefaultAsyncWaiter() {
186         return this;
187     }
188
189     /**
190      * @see AsyncWaiter#asyncWait(Handle, Core.HandleSignals, long, Callback)
191      */
192     @Override
193     public Cancellable asyncWait(Handle handle, HandleSignals signals, long deadline,
194             Callback callback) {
195         return nativeAsyncWait(getMojoHandle(handle), signals.getFlags(), deadline, callback);
196     }
197
198     int closeWithResult(int mojoHandle) {
199         return nativeClose(mojoHandle);
200     }
201
202     void close(int mojoHandle) {
203         int mojoResult = nativeClose(mojoHandle);
204         if (mojoResult != MojoResult.OK) {
205             throw new MojoException(mojoResult);
206         }
207     }
208
209     /**
210      * @see MessagePipeHandle#writeMessage(ByteBuffer, List, MessagePipeHandle.WriteFlags)
211      */
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));
219             }
220             handlesBuffer.position(0);
221         }
222         int mojoResult = nativeWriteMessage(pipeHandle.getMojoHandle(), bytes,
223                 bytes == null ? 0 : bytes.limit(), handlesBuffer,
224                 flags.getFlags());
225         if (mojoResult != MojoResult.OK) {
226             throw new MojoException(mojoResult);
227         }
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();
233                 }
234             }
235         }
236     }
237
238     /**
239      * @see MessagePipeHandle#readMessage(ByteBuffer, int, MessagePipeHandle.ReadFlags)
240      */
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);
247         }
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());
254         }
255
256         if (result.getMojoResult() == MojoResult.OK) {
257             if (bytes != null) {
258                 bytes.position(0);
259                 bytes.limit(result.getMessageSize());
260             }
261
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));
267             }
268             result.setHandles(handles);
269         }
270         return result;
271     }
272
273     /**
274      * @see ConsumerHandle#discardData(int, DataPipe.ReadFlags)
275      */
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);
280         if (result < 0) {
281             throw new MojoException(result);
282         }
283         return result;
284     }
285
286     /**
287      * @see ConsumerHandle#readData(ByteBuffer, DataPipe.ReadFlags)
288      */
289     int readData(DataPipeConsumerHandleImpl handle, ByteBuffer elements,
290             DataPipe.ReadFlags flags) {
291         int result = nativeReadData(handle.getMojoHandle(), elements,
292                 elements == null ? 0 : elements.capacity(),
293                 flags.getFlags());
294         if (result < 0) {
295             throw new MojoException(result);
296         }
297         if (elements != null) {
298             elements.limit(result);
299         }
300         return result;
301     }
302
303     /**
304      * @see ConsumerHandle#beginReadData(int, DataPipe.ReadFlags)
305      */
306     ByteBuffer beginReadData(DataPipeConsumerHandleImpl handle,
307             int numBytes, DataPipe.ReadFlags flags) {
308         NativeCodeAndBufferResult result = nativeBeginReadData(
309                 handle.getMojoHandle(),
310                 numBytes,
311                 flags.getFlags());
312         if (result.getMojoResult() != MojoResult.OK) {
313             throw new MojoException(result.getMojoResult());
314         }
315         return result.getBuffer().asReadOnlyBuffer();
316     }
317
318     /**
319      * @see ConsumerHandle#endReadData(int)
320      */
321     void endReadData(DataPipeConsumerHandleImpl handle,
322             int numBytesRead) {
323         int result = nativeEndReadData(handle.getMojoHandle(), numBytesRead);
324         if (result != MojoResult.OK) {
325             throw new MojoException(result);
326         }
327     }
328
329     /**
330      * @see ProducerHandle#writeData(ByteBuffer, DataPipe.WriteFlags)
331      */
332     int writeData(DataPipeProducerHandleImpl handle, ByteBuffer elements,
333             DataPipe.WriteFlags flags) {
334         return nativeWriteData(handle.getMojoHandle(), elements, elements.limit(),
335                 flags.getFlags());
336     }
337
338     /**
339      * @see ProducerHandle#beginWriteData(int, DataPipe.WriteFlags)
340      */
341     ByteBuffer beginWriteData(DataPipeProducerHandleImpl handle,
342             int numBytes, DataPipe.WriteFlags flags) {
343         NativeCodeAndBufferResult result = nativeBeginWriteData(
344                 handle.getMojoHandle(),
345                 numBytes,
346                 flags.getFlags());
347         if (result.getMojoResult() != MojoResult.OK) {
348             throw new MojoException(result.getMojoResult());
349         }
350         return result.getBuffer();
351     }
352
353     /**
354      * @see ProducerHandle#endWriteData(int)
355      */
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);
361         }
362     }
363
364     /**
365      * @see SharedBufferHandle#duplicate(DuplicateOptions)
366      */
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());
374         }
375         NativeCreationResult result = nativeDuplicate(handle.getMojoHandle(),
376                 optionsBuffer);
377         if (result.getMojoResult() != MojoResult.OK) {
378             throw new MojoException(result.getMojoResult());
379         }
380         assert result.getMojoHandle2() == 0;
381         return new SharedBufferHandleImpl(this, result.getMojoHandle1());
382     }
383
384     /**
385      * @see SharedBufferHandle#map(long, long, MapFlags)
386      */
387     ByteBuffer map(SharedBufferHandleImpl handle, long offset, long numBytes,
388             MapFlags flags) {
389         NativeCodeAndBufferResult result = nativeMap(handle.getMojoHandle(), offset, numBytes,
390                 flags.getFlags());
391         if (result.getMojoResult() != MojoResult.OK) {
392             throw new MojoException(result.getMojoResult());
393         }
394         return result.getBuffer();
395     }
396
397     /**
398      * @see SharedBufferHandle#unmap(ByteBuffer)
399      */
400     void unmap(ByteBuffer buffer) {
401         int result = nativeUnmap(buffer);
402         if (result != MojoResult.OK) {
403             throw new MojoException(result);
404         }
405     }
406
407     /**
408      * @return the mojo handle associated to the given handle, considering invalid handles.
409      */
410     private int getMojoHandle(Handle handle) {
411         if (handle.isValid()) {
412             return ((HandleBase) handle).getMojoHandle();
413         }
414         return 0;
415     }
416
417     private static boolean isUnrecoverableError(int code) {
418         switch (code) {
419             case MojoResult.OK:
420             case MojoResult.DEADLINE_EXCEEDED:
421             case MojoResult.CANCELLED:
422             case MojoResult.FAILED_PRECONDITION:
423                 return false;
424             default:
425                 return true;
426         }
427     }
428
429     private static int filterMojoResult(int code) {
430         if (code >= 0) {
431             return MojoResult.OK;
432         }
433         return code;
434     }
435
436     private static int filterMojoResultForWait(int code) {
437         int finalCode = filterMojoResult(code);
438         if (isUnrecoverableError(finalCode)) {
439             throw new MojoException(finalCode);
440         }
441         return finalCode;
442     }
443
444     private static ByteBuffer allocateDirectBuffer(int capacity) {
445         ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
446         buffer.order(ByteOrder.nativeOrder());
447         return buffer;
448     }
449
450     private static class NativeCodeAndBufferResult {
451         private int mMojoResult;
452         private ByteBuffer mBuffer;
453
454         /**
455          * @return the mojoResult
456          */
457         public int getMojoResult() {
458             return mMojoResult;
459         }
460
461         /**
462          * @param mojoResult the mojoResult to set
463          */
464         public void setMojoResult(int mojoResult) {
465             mMojoResult = mojoResult;
466         }
467
468         /**
469          * @return the buffer
470          */
471         public ByteBuffer getBuffer() {
472             return mBuffer;
473         }
474
475         /**
476          * @param buffer the buffer to set
477          */
478         public void setBuffer(ByteBuffer buffer) {
479             mBuffer = buffer;
480         }
481
482     }
483
484     /**
485      * Implementation of {@link org.chromium.mojo.system.AsyncWaiter.Cancellable}.
486      */
487     private class AsyncWaiterCancellableImpl implements AsyncWaiter.Cancellable {
488
489         private final long mId;
490         private final long mDataPtr;
491         private boolean mActive = true;
492
493         private AsyncWaiterCancellableImpl(long id, long dataPtr) {
494             this.mId = id;
495             this.mDataPtr = dataPtr;
496         }
497
498         /**
499          * @see org.chromium.mojo.system.AsyncWaiter.Cancellable#cancel()
500          */
501         @Override
502         public void cancel() {
503             if (mActive) {
504                 mActive = false;
505                 nativeCancelAsyncWait(mId, mDataPtr);
506             }
507         }
508
509         private boolean isActive() {
510             return mActive;
511         }
512
513         private void deactivate() {
514             mActive = false;
515         }
516     }
517
518     @CalledByNative
519     private AsyncWaiterCancellableImpl newAsyncWaiterCancellableImpl(long id, long dataPtr) {
520         return new AsyncWaiterCancellableImpl(id, dataPtr);
521     }
522
523     @CalledByNative
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.
529             return;
530         }
531         cancellable.deactivate();
532         int finalCode = filterMojoResult(mojoResult);
533         if (isUnrecoverableError(finalCode)) {
534             callback.onError(new MojoException(finalCode));
535             return;
536         }
537         callback.onResult(finalCode);
538     }
539
540     @CalledByNative
541     private static NativeCodeAndBufferResult newNativeCodeAndBufferResult(int mojoResult,
542             ByteBuffer buffer) {
543         NativeCodeAndBufferResult result = new NativeCodeAndBufferResult();
544         result.setMojoResult(mojoResult);
545         result.setBuffer(buffer);
546         return result;
547     }
548
549     @CalledByNative
550     private static MessagePipeHandle.ReadMessageResult newReadMessageResult(int mojoResult,
551             int messageSize,
552             int handlesCount) {
553         MessagePipeHandle.ReadMessageResult result = new MessagePipeHandle.ReadMessageResult();
554         if (mojoResult >= 0) {
555             result.setMojoResult(MojoResult.OK);
556         } else {
557             result.setMojoResult(mojoResult);
558         }
559         result.setMessageSize(messageSize);
560         result.setHandlesCount(handlesCount);
561         return result;
562     }
563
564     private static class NativeCreationResult {
565         private int mMojoResult;
566         private int mMojoHandle1;
567         private int mMojoHandle2;
568
569         /**
570          * @return the mojoResult
571          */
572         public int getMojoResult() {
573             return mMojoResult;
574         }
575
576         /**
577          * @param mojoResult the mojoResult to set
578          */
579         public void setMojoResult(int mojoResult) {
580             mMojoResult = mojoResult;
581         }
582
583         /**
584          * @return the mojoHandle1
585          */
586         public int getMojoHandle1() {
587             return mMojoHandle1;
588         }
589
590         /**
591          * @param mojoHandle1 the mojoHandle1 to set
592          */
593         public void setMojoHandle1(int mojoHandle1) {
594             mMojoHandle1 = mojoHandle1;
595         }
596
597         /**
598          * @return the mojoHandle2
599          */
600         public int getMojoHandle2() {
601             return mMojoHandle2;
602         }
603
604         /**
605          * @param mojoHandle2 the mojoHandle2 to set
606          */
607         public void setMojoHandle2(int mojoHandle2) {
608             mMojoHandle2 = mojoHandle2;
609         }
610     }
611
612     @CalledByNative
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);
619         return result;
620     }
621
622     private native long nativeGetTimeTicksNow();
623
624     private native int nativeWaitMany(ByteBuffer buffer, long deadline);
625
626     private native NativeCreationResult nativeCreateMessagePipe(ByteBuffer optionsBuffer);
627
628     private native NativeCreationResult nativeCreateDataPipe(ByteBuffer optionsBuffer);
629
630     private native NativeCreationResult nativeCreateSharedBuffer(ByteBuffer optionsBuffer,
631             long numBytes);
632
633     private native int nativeClose(int mojoHandle);
634
635     private native int nativeWait(int mojoHandle, int signals, long deadline);
636
637     private native int nativeWriteMessage(int mojoHandle, ByteBuffer bytes, int numBytes,
638             ByteBuffer handlesBuffer, int flags);
639
640     private native MessagePipeHandle.ReadMessageResult nativeReadMessage(int mojoHandle,
641             ByteBuffer bytes,
642             ByteBuffer handlesBuffer,
643             int flags);
644
645     private native int nativeReadData(int mojoHandle, ByteBuffer elements, int elementsSize,
646             int flags);
647
648     private native NativeCodeAndBufferResult nativeBeginReadData(int mojoHandle, int numBytes,
649             int flags);
650
651     private native int nativeEndReadData(int mojoHandle, int numBytesRead);
652
653     private native int nativeWriteData(int mojoHandle, ByteBuffer elements, int limit, int flags);
654
655     private native NativeCodeAndBufferResult nativeBeginWriteData(int mojoHandle, int numBytes,
656             int flags);
657
658     private native int nativeEndWriteData(int mojoHandle, int numBytesWritten);
659
660     private native NativeCreationResult nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer);
661
662     private native NativeCodeAndBufferResult nativeMap(int mojoHandle, long offset, long numBytes,
663             int flags);
664
665     private native int nativeUnmap(ByteBuffer buffer);
666
667     private native AsyncWaiterCancellableImpl nativeAsyncWait(int mojoHandle, int signals,
668             long deadline, AsyncWaiter.Callback callback);
669
670     private native void nativeCancelAsyncWait(long mId, long dataPtr);
671 }