Upstream version 9.38.198.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         nativeConstructor();
68     }
69
70     /**
71      * @see Core#getTimeTicksNow()
72      */
73     @Override
74     public long getTimeTicksNow() {
75         return nativeGetTimeTicksNow();
76     }
77
78     /**
79      * @see Core#waitMany(List, long)
80      */
81     @Override
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);
86         int index = 0;
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());
91             index++;
92         }
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));
99         return result;
100     }
101
102     /**
103      * @see Core#wait(Handle, HandleSignals, long)
104      */
105     @Override
106     public int wait(Handle handle, HandleSignals signals, long deadline) {
107         return filterMojoResultForWait(nativeWait(getMojoHandle(handle),
108                 signals.getFlags(), deadline));
109     }
110
111     /**
112      * @see Core#createMessagePipe(MessagePipeHandle.CreateOptions)
113      */
114     @Override
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());
122         }
123         NativeCreationResult result = nativeCreateMessagePipe(optionsBuffer);
124         if (result.getMojoResult() != MojoResult.OK) {
125             throw new MojoException(result.getMojoResult());
126         }
127         return Pair.<MessagePipeHandle, MessagePipeHandle> create(
128                 new MessagePipeHandleImpl(this, result.getMojoHandle1()),
129                 new MessagePipeHandleImpl(this, result.getMojoHandle2()));
130     }
131
132     /**
133      * @see Core#createDataPipe(DataPipe.CreateOptions)
134      */
135     @Override
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());
144         }
145         NativeCreationResult result = nativeCreateDataPipe(optionsBuffer);
146         if (result.getMojoResult() != MojoResult.OK) {
147             throw new MojoException(result.getMojoResult());
148         }
149         return Pair.<ProducerHandle, ConsumerHandle> create(
150                 new DataPipeProducerHandleImpl(this, result.getMojoHandle1()),
151                 new DataPipeConsumerHandleImpl(this, result.getMojoHandle2()));
152     }
153
154     /**
155      * @see Core#createSharedBuffer(SharedBufferHandle.CreateOptions, long)
156      */
157     @Override
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());
165         }
166         NativeCreationResult result = nativeCreateSharedBuffer(optionsBuffer, numBytes);
167         if (result.getMojoResult() != MojoResult.OK) {
168             throw new MojoException(result.getMojoResult());
169         }
170         assert result.getMojoHandle2() == 0;
171         return new SharedBufferHandleImpl(this, result.getMojoHandle1());
172     }
173
174     /**
175      * @see Core#getDefaultAsyncWaiter()
176      */
177     @Override
178     public AsyncWaiter getDefaultAsyncWaiter() {
179         return this;
180     }
181
182     /**
183      * @see AsyncWaiter#asyncWait(Handle, Core.HandleSignals, long, Callback)
184      */
185     @Override
186     public Cancellable asyncWait(Handle handle, HandleSignals signals, long deadline,
187             Callback callback) {
188         return nativeAsyncWait(getMojoHandle(handle), signals.getFlags(), deadline, callback);
189     }
190
191     int closeWithResult(int mojoHandle) {
192         return nativeClose(mojoHandle);
193     }
194
195     void close(int mojoHandle) {
196         int mojoResult = nativeClose(mojoHandle);
197         if (mojoResult != MojoResult.OK) {
198             throw new MojoException(mojoResult);
199         }
200     }
201
202     /**
203      * @see MessagePipeHandle#writeMessage(ByteBuffer, List, MessagePipeHandle.WriteFlags)
204      */
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));
212             }
213             handlesBuffer.position(0);
214         }
215         int mojoResult = nativeWriteMessage(pipeHandle.getMojoHandle(), bytes,
216                 bytes == null ? 0 : bytes.limit(), handlesBuffer,
217                 flags.getFlags());
218         if (mojoResult != MojoResult.OK) {
219             throw new MojoException(mojoResult);
220         }
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();
226                 }
227             }
228         }
229     }
230
231     /**
232      * @see MessagePipeHandle#readMessage(ByteBuffer, int, MessagePipeHandle.ReadFlags)
233      */
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);
240         }
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());
247         }
248
249         if (result.getMojoResult() == MojoResult.OK) {
250             if (bytes != null) {
251                 bytes.position(0);
252                 bytes.limit(result.getMessageSize());
253             }
254
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));
260             }
261             result.setHandles(handles);
262         }
263         return result;
264     }
265
266     /**
267      * @see ConsumerHandle#discardData(int, DataPipe.ReadFlags)
268      */
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);
273         if (result < 0) {
274             throw new MojoException(result);
275         }
276         return result;
277     }
278
279     /**
280      * @see ConsumerHandle#readData(ByteBuffer, DataPipe.ReadFlags)
281      */
282     int readData(DataPipeConsumerHandleImpl handle, ByteBuffer elements,
283             DataPipe.ReadFlags flags) {
284         int result = nativeReadData(handle.getMojoHandle(), elements,
285                 elements == null ? 0 : elements.capacity(),
286                 flags.getFlags());
287         if (result < 0) {
288             throw new MojoException(result);
289         }
290         if (elements != null) {
291             elements.limit(result);
292         }
293         return result;
294     }
295
296     /**
297      * @see ConsumerHandle#beginReadData(int, DataPipe.ReadFlags)
298      */
299     ByteBuffer beginReadData(DataPipeConsumerHandleImpl handle,
300             int numBytes, DataPipe.ReadFlags flags) {
301         NativeCodeAndBufferResult result = nativeBeginReadData(
302                 handle.getMojoHandle(),
303                 numBytes,
304                 flags.getFlags());
305         if (result.getMojoResult() != MojoResult.OK) {
306             throw new MojoException(result.getMojoResult());
307         }
308         return result.getBuffer().asReadOnlyBuffer();
309     }
310
311     /**
312      * @see ConsumerHandle#endReadData(int)
313      */
314     void endReadData(DataPipeConsumerHandleImpl handle,
315             int numBytesRead) {
316         int result = nativeEndReadData(handle.getMojoHandle(), numBytesRead);
317         if (result != MojoResult.OK) {
318             throw new MojoException(result);
319         }
320     }
321
322     /**
323      * @see ProducerHandle#writeData(ByteBuffer, DataPipe.WriteFlags)
324      */
325     int writeData(DataPipeProducerHandleImpl handle, ByteBuffer elements,
326             DataPipe.WriteFlags flags) {
327         return nativeWriteData(handle.getMojoHandle(), elements, elements.limit(),
328                 flags.getFlags());
329     }
330
331     /**
332      * @see ProducerHandle#beginWriteData(int, DataPipe.WriteFlags)
333      */
334     ByteBuffer beginWriteData(DataPipeProducerHandleImpl handle,
335             int numBytes, DataPipe.WriteFlags flags) {
336         NativeCodeAndBufferResult result = nativeBeginWriteData(
337                 handle.getMojoHandle(),
338                 numBytes,
339                 flags.getFlags());
340         if (result.getMojoResult() != MojoResult.OK) {
341             throw new MojoException(result.getMojoResult());
342         }
343         return result.getBuffer();
344     }
345
346     /**
347      * @see ProducerHandle#endWriteData(int)
348      */
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);
354         }
355     }
356
357     /**
358      * @see SharedBufferHandle#duplicate(DuplicateOptions)
359      */
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());
367         }
368         NativeCreationResult result = nativeDuplicate(handle.getMojoHandle(),
369                 optionsBuffer);
370         if (result.getMojoResult() != MojoResult.OK) {
371             throw new MojoException(result.getMojoResult());
372         }
373         assert result.getMojoHandle2() == 0;
374         return new SharedBufferHandleImpl(this, result.getMojoHandle1());
375     }
376
377     /**
378      * @see SharedBufferHandle#map(long, long, MapFlags)
379      */
380     ByteBuffer map(SharedBufferHandleImpl handle, long offset, long numBytes,
381             MapFlags flags) {
382         NativeCodeAndBufferResult result = nativeMap(handle.getMojoHandle(), offset, numBytes,
383                 flags.getFlags());
384         if (result.getMojoResult() != MojoResult.OK) {
385             throw new MojoException(result.getMojoResult());
386         }
387         return result.getBuffer();
388     }
389
390     /**
391      * @see SharedBufferHandle#unmap(ByteBuffer)
392      */
393     void unmap(ByteBuffer buffer) {
394         int result = nativeUnmap(buffer);
395         if (result != MojoResult.OK) {
396             throw new MojoException(result);
397         }
398     }
399
400     /**
401      * @return the mojo handle associated to the given handle, considering invalid handles.
402      */
403     private int getMojoHandle(Handle handle) {
404         if (handle.isValid()) {
405             return ((HandleBase) handle).getMojoHandle();
406         }
407         return 0;
408     }
409
410     private static boolean isUnrecoverableError(int code) {
411         switch (code) {
412             case MojoResult.OK:
413             case MojoResult.DEADLINE_EXCEEDED:
414             case MojoResult.CANCELLED:
415             case MojoResult.FAILED_PRECONDITION:
416                 return false;
417             default:
418                 return true;
419         }
420     }
421
422     private static int filterMojoResult(int code) {
423         if (code >= 0) {
424             return MojoResult.OK;
425         }
426         return code;
427     }
428
429     private static int filterMojoResultForWait(int code) {
430         int finalCode = filterMojoResult(code);
431         if (isUnrecoverableError(finalCode)) {
432             throw new MojoException(finalCode);
433         }
434         return finalCode;
435     }
436
437     private static ByteBuffer allocateDirectBuffer(int capacity) {
438         ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);
439         buffer.order(ByteOrder.nativeOrder());
440         return buffer;
441     }
442
443     private static class NativeCodeAndBufferResult {
444         private int mMojoResult;
445         private ByteBuffer mBuffer;
446
447         /**
448          * @return the mojoResult
449          */
450         public int getMojoResult() {
451             return mMojoResult;
452         }
453
454         /**
455          * @param mojoResult the mojoResult to set
456          */
457         public void setMojoResult(int mojoResult) {
458             mMojoResult = mojoResult;
459         }
460
461         /**
462          * @return the buffer
463          */
464         public ByteBuffer getBuffer() {
465             return mBuffer;
466         }
467
468         /**
469          * @param buffer the buffer to set
470          */
471         public void setBuffer(ByteBuffer buffer) {
472             mBuffer = buffer;
473         }
474
475     }
476
477     /**
478      * Implementation of {@link org.chromium.mojo.system.AsyncWaiter.Cancellable}.
479      */
480     private class AsyncWaiterCancellableImpl implements AsyncWaiter.Cancellable {
481
482         private final long mId;
483         private final long mDataPtr;
484         private boolean mActive = true;
485
486         private AsyncWaiterCancellableImpl(long id, long dataPtr) {
487             this.mId = id;
488             this.mDataPtr = dataPtr;
489         }
490
491         /**
492          * @see org.chromium.mojo.system.AsyncWaiter.Cancellable#cancel()
493          */
494         @Override
495         public void cancel() {
496             if (mActive) {
497                 mActive = false;
498                 nativeCancelAsyncWait(mId, mDataPtr);
499             }
500         }
501
502         private boolean isActive() {
503             return mActive;
504         }
505
506         private void deactivate() {
507             mActive = false;
508         }
509     }
510
511     @CalledByNative
512     private AsyncWaiterCancellableImpl newAsyncWaiterCancellableImpl(long id, long dataPtr) {
513         return new AsyncWaiterCancellableImpl(id, dataPtr);
514     }
515
516     @CalledByNative
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.
522             return;
523         }
524         cancellable.deactivate();
525         int finalCode = filterMojoResult(mojoResult);
526         if (isUnrecoverableError(finalCode)) {
527             callback.onError(new MojoException(finalCode));
528             return;
529         }
530         callback.onResult(finalCode);
531     }
532
533     @CalledByNative
534     private static NativeCodeAndBufferResult newNativeCodeAndBufferResult(int mojoResult,
535             ByteBuffer buffer) {
536         NativeCodeAndBufferResult result = new NativeCodeAndBufferResult();
537         result.setMojoResult(mojoResult);
538         result.setBuffer(buffer);
539         return result;
540     }
541
542     @CalledByNative
543     private static MessagePipeHandle.ReadMessageResult newReadMessageResult(int mojoResult,
544             int messageSize,
545             int handlesCount) {
546         MessagePipeHandle.ReadMessageResult result = new MessagePipeHandle.ReadMessageResult();
547         if (mojoResult >= 0) {
548             result.setMojoResult(MojoResult.OK);
549         } else {
550             result.setMojoResult(mojoResult);
551         }
552         result.setMessageSize(messageSize);
553         result.setHandlesCount(handlesCount);
554         return result;
555     }
556
557     private static class NativeCreationResult {
558         private int mMojoResult;
559         private int mMojoHandle1;
560         private int mMojoHandle2;
561
562         /**
563          * @return the mojoResult
564          */
565         public int getMojoResult() {
566             return mMojoResult;
567         }
568
569         /**
570          * @param mojoResult the mojoResult to set
571          */
572         public void setMojoResult(int mojoResult) {
573             mMojoResult = mojoResult;
574         }
575
576         /**
577          * @return the mojoHandle1
578          */
579         public int getMojoHandle1() {
580             return mMojoHandle1;
581         }
582
583         /**
584          * @param mojoHandle1 the mojoHandle1 to set
585          */
586         public void setMojoHandle1(int mojoHandle1) {
587             mMojoHandle1 = mojoHandle1;
588         }
589
590         /**
591          * @return the mojoHandle2
592          */
593         public int getMojoHandle2() {
594             return mMojoHandle2;
595         }
596
597         /**
598          * @param mojoHandle2 the mojoHandle2 to set
599          */
600         public void setMojoHandle2(int mojoHandle2) {
601             mMojoHandle2 = mojoHandle2;
602         }
603     }
604
605     @CalledByNative
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);
612         return result;
613     }
614
615     private native void nativeConstructor();
616
617     private native long nativeGetTimeTicksNow();
618
619     private native int nativeWaitMany(ByteBuffer buffer, long deadline);
620
621     private native NativeCreationResult nativeCreateMessagePipe(ByteBuffer optionsBuffer);
622
623     private native NativeCreationResult nativeCreateDataPipe(ByteBuffer optionsBuffer);
624
625     private native NativeCreationResult nativeCreateSharedBuffer(ByteBuffer optionsBuffer,
626             long numBytes);
627
628     private native int nativeClose(int mojoHandle);
629
630     private native int nativeWait(int mojoHandle, int signals, long deadline);
631
632     private native int nativeWriteMessage(int mojoHandle, ByteBuffer bytes, int numBytes,
633             ByteBuffer handlesBuffer, int flags);
634
635     private native MessagePipeHandle.ReadMessageResult nativeReadMessage(int mojoHandle,
636             ByteBuffer bytes,
637             ByteBuffer handlesBuffer,
638             int flags);
639
640     private native int nativeReadData(int mojoHandle, ByteBuffer elements, int elementsSize,
641             int flags);
642
643     private native NativeCodeAndBufferResult nativeBeginReadData(int mojoHandle, int numBytes,
644             int flags);
645
646     private native int nativeEndReadData(int mojoHandle, int numBytesRead);
647
648     private native int nativeWriteData(int mojoHandle, ByteBuffer elements, int limit, int flags);
649
650     private native NativeCodeAndBufferResult nativeBeginWriteData(int mojoHandle, int numBytes,
651             int flags);
652
653     private native int nativeEndWriteData(int mojoHandle, int numBytesWritten);
654
655     private native NativeCreationResult nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer);
656
657     private native NativeCodeAndBufferResult nativeMap(int mojoHandle, long offset, long numBytes,
658             int flags);
659
660     private native int nativeUnmap(ByteBuffer buffer);
661
662     private native AsyncWaiterCancellableImpl nativeAsyncWait(int mojoHandle, int signals,
663             long deadline, AsyncWaiter.Callback callback);
664
665     private native void nativeCancelAsyncWait(long mId, long dataPtr);
666 }