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.annotations.CalledByNative;
8 import org.chromium.base.annotations.JNINamespace;
9 import org.chromium.base.annotations.MainDex;
10 import org.chromium.mojo.system.Core;
11 import org.chromium.mojo.system.Core.HandleSignalsState;
12 import org.chromium.mojo.system.DataPipe;
13 import org.chromium.mojo.system.DataPipe.ConsumerHandle;
14 import org.chromium.mojo.system.DataPipe.ProducerHandle;
15 import org.chromium.mojo.system.Handle;
16 import org.chromium.mojo.system.MessagePipeHandle;
17 import org.chromium.mojo.system.MojoException;
18 import org.chromium.mojo.system.MojoResult;
19 import org.chromium.mojo.system.Pair;
20 import org.chromium.mojo.system.ResultAnd;
21 import org.chromium.mojo.system.RunLoop;
22 import org.chromium.mojo.system.SharedBufferHandle;
23 import org.chromium.mojo.system.SharedBufferHandle.DuplicateOptions;
24 import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
25 import org.chromium.mojo.system.UntypedHandle;
26 import org.chromium.mojo.system.Watcher;
27 
28 import java.nio.ByteBuffer;
29 import java.nio.ByteOrder;
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 /**
34  * Implementation of {@link Core}.
35  */
36 @JNINamespace("mojo::android")
37 @MainDex
38 public class CoreImpl implements Core {
39     /**
40      * Discard flag for the |MojoReadData| operation.
41      */
42     private static final int MOJO_READ_DATA_FLAG_DISCARD = 1 << 1;
43 
44     /**
45      * the size of a handle, in bytes.
46      */
47     private static final int HANDLE_SIZE = 4;
48 
49     /**
50      * the size of a flag, in bytes.
51      */
52     private static final int FLAG_SIZE = 4;
53 
54     /**
55      * The mojo handle for an invalid handle.
56      */
57     static final int INVALID_HANDLE = 0;
58 
59     private static class LazyHolder { private static final Core INSTANCE = new CoreImpl(); }
60 
61     /**
62      * The run loop for the current thread.
63      */
64     private final ThreadLocal<BaseRunLoop> mCurrentRunLoop = new ThreadLocal<BaseRunLoop>();
65 
66     /**
67      * The offset needed to get an aligned buffer.
68      */
69     private final int mByteBufferOffset;
70 
71     /**
72      * @return the instance.
73      */
getInstance()74     public static Core getInstance() {
75         return LazyHolder.INSTANCE;
76     }
77 
CoreImpl()78     private CoreImpl() {
79         // Fix for the ART runtime, before:
80         // https://android.googlesource.com/platform/libcore/+/fb6c80875a8a8d0a9628562f89c250b6a962e824%5E!/
81         // This assumes consistent allocation.
82         mByteBufferOffset = nativeGetNativeBufferOffset(ByteBuffer.allocateDirect(8), 8);
83     }
84 
85     /**
86      * @see Core#getTimeTicksNow()
87      */
88     @Override
getTimeTicksNow()89     public long getTimeTicksNow() {
90         return nativeGetTimeTicksNow();
91     }
92 
93     /**
94      * @see Core#createMessagePipe(MessagePipeHandle.CreateOptions)
95      */
96     @Override
createMessagePipe( MessagePipeHandle.CreateOptions options)97     public Pair<MessagePipeHandle, MessagePipeHandle> createMessagePipe(
98             MessagePipeHandle.CreateOptions options) {
99         ByteBuffer optionsBuffer = null;
100         if (options != null) {
101             optionsBuffer = allocateDirectBuffer(8);
102             optionsBuffer.putInt(0, 8);
103             optionsBuffer.putInt(4, options.getFlags().getFlags());
104         }
105         ResultAnd<IntegerPair> result = nativeCreateMessagePipe(optionsBuffer);
106         if (result.getMojoResult() != MojoResult.OK) {
107             throw new MojoException(result.getMojoResult());
108         }
109         return Pair.<MessagePipeHandle, MessagePipeHandle>create(
110                 new MessagePipeHandleImpl(this, result.getValue().first),
111                 new MessagePipeHandleImpl(this, result.getValue().second));
112     }
113 
114     /**
115      * @see Core#createDataPipe(DataPipe.CreateOptions)
116      */
117     @Override
createDataPipe(DataPipe.CreateOptions options)118     public Pair<ProducerHandle, ConsumerHandle> createDataPipe(DataPipe.CreateOptions options) {
119         ByteBuffer optionsBuffer = null;
120         if (options != null) {
121             optionsBuffer = allocateDirectBuffer(16);
122             optionsBuffer.putInt(0, 16);
123             optionsBuffer.putInt(4, options.getFlags().getFlags());
124             optionsBuffer.putInt(8, options.getElementNumBytes());
125             optionsBuffer.putInt(12, options.getCapacityNumBytes());
126         }
127         ResultAnd<IntegerPair> result = nativeCreateDataPipe(optionsBuffer);
128         if (result.getMojoResult() != MojoResult.OK) {
129             throw new MojoException(result.getMojoResult());
130         }
131         return Pair.<ProducerHandle, ConsumerHandle>create(
132                 new DataPipeProducerHandleImpl(this, result.getValue().first),
133                 new DataPipeConsumerHandleImpl(this, result.getValue().second));
134     }
135 
136     /**
137      * @see Core#createSharedBuffer(SharedBufferHandle.CreateOptions, long)
138      */
139     @Override
createSharedBuffer( SharedBufferHandle.CreateOptions options, long numBytes)140     public SharedBufferHandle createSharedBuffer(
141             SharedBufferHandle.CreateOptions options, long numBytes) {
142         ByteBuffer optionsBuffer = null;
143         if (options != null) {
144             optionsBuffer = allocateDirectBuffer(8);
145             optionsBuffer.putInt(0, 8);
146             optionsBuffer.putInt(4, options.getFlags().getFlags());
147         }
148         ResultAnd<Integer> result = nativeCreateSharedBuffer(optionsBuffer, numBytes);
149         if (result.getMojoResult() != MojoResult.OK) {
150             throw new MojoException(result.getMojoResult());
151         }
152         return new SharedBufferHandleImpl(this, result.getValue());
153     }
154 
155     /**
156      * @see org.chromium.mojo.system.Core#acquireNativeHandle(int)
157      */
158     @Override
acquireNativeHandle(int handle)159     public UntypedHandle acquireNativeHandle(int handle) {
160         return new UntypedHandleImpl(this, handle);
161     }
162 
163     /**
164      * @see Core#getWatcher()
165      */
166     @Override
getWatcher()167     public Watcher getWatcher() {
168         return new WatcherImpl();
169     }
170 
171     /**
172      * @see Core#createDefaultRunLoop()
173      */
174     @Override
createDefaultRunLoop()175     public RunLoop createDefaultRunLoop() {
176         if (mCurrentRunLoop.get() != null) {
177             throw new MojoException(MojoResult.FAILED_PRECONDITION);
178         }
179         BaseRunLoop runLoop = new BaseRunLoop(this);
180         mCurrentRunLoop.set(runLoop);
181         return runLoop;
182     }
183 
184     /**
185      * @see Core#getCurrentRunLoop()
186      */
187     @Override
getCurrentRunLoop()188     public RunLoop getCurrentRunLoop() {
189         return mCurrentRunLoop.get();
190     }
191 
192     /**
193      * Remove the current run loop.
194      */
clearCurrentRunLoop()195     void clearCurrentRunLoop() {
196         mCurrentRunLoop.remove();
197     }
198 
closeWithResult(int mojoHandle)199     int closeWithResult(int mojoHandle) {
200         return nativeClose(mojoHandle);
201     }
202 
close(int mojoHandle)203     void close(int mojoHandle) {
204         int mojoResult = nativeClose(mojoHandle);
205         if (mojoResult != MojoResult.OK) {
206             throw new MojoException(mojoResult);
207         }
208     }
209 
queryHandleSignalsState(int mojoHandle)210     HandleSignalsState queryHandleSignalsState(int mojoHandle) {
211         ByteBuffer buffer = allocateDirectBuffer(8);
212         int result = nativeQueryHandleSignalsState(mojoHandle, buffer);
213         if (result != MojoResult.OK) throw new MojoException(result);
214         return new HandleSignalsState(
215                 new HandleSignals(buffer.getInt(0)), new HandleSignals(buffer.getInt(4)));
216     }
217 
218     /**
219      * @see MessagePipeHandle#writeMessage(ByteBuffer, List, MessagePipeHandle.WriteFlags)
220      */
writeMessage(MessagePipeHandleImpl pipeHandle, ByteBuffer bytes, List<? extends Handle> handles, MessagePipeHandle.WriteFlags flags)221     void writeMessage(MessagePipeHandleImpl pipeHandle, ByteBuffer bytes,
222             List<? extends Handle> handles, MessagePipeHandle.WriteFlags flags) {
223         ByteBuffer handlesBuffer = null;
224         if (handles != null && !handles.isEmpty()) {
225             handlesBuffer = allocateDirectBuffer(handles.size() * HANDLE_SIZE);
226             for (Handle handle : handles) {
227                 handlesBuffer.putInt(getMojoHandle(handle));
228             }
229             handlesBuffer.position(0);
230         }
231         int mojoResult = nativeWriteMessage(pipeHandle.getMojoHandle(), bytes,
232                 bytes == null ? 0 : bytes.limit(), handlesBuffer, flags.getFlags());
233         if (mojoResult != MojoResult.OK) {
234             throw new MojoException(mojoResult);
235         }
236         // Success means the handles have been invalidated.
237         if (handles != null) {
238             for (Handle handle : handles) {
239                 if (handle.isValid()) {
240                     ((HandleBase) handle).invalidateHandle();
241                 }
242             }
243         }
244     }
245 
246     /**
247      * @see MessagePipeHandle#readMessage(MessagePipeHandle.ReadFlags)
248      */
readMessage( MessagePipeHandleImpl handle, MessagePipeHandle.ReadFlags flags)249     ResultAnd<MessagePipeHandle.ReadMessageResult> readMessage(
250             MessagePipeHandleImpl handle, MessagePipeHandle.ReadFlags flags) {
251         ResultAnd<MessagePipeHandle.ReadMessageResult> result =
252                 nativeReadMessage(handle.getMojoHandle(), flags.getFlags());
253         if (result.getMojoResult() != MojoResult.OK
254                 && result.getMojoResult() != MojoResult.SHOULD_WAIT) {
255             throw new MojoException(result.getMojoResult());
256         }
257 
258         MessagePipeHandle.ReadMessageResult readResult = result.getValue();
259         int[] rawHandles = readResult.mRawHandles;
260         if (rawHandles != null && rawHandles.length != 0) {
261             readResult.mHandles = new ArrayList<UntypedHandle>(rawHandles.length);
262             for (int rawHandle : rawHandles) {
263                 readResult.mHandles.add(new UntypedHandleImpl(this, rawHandle));
264             }
265         } else {
266             readResult.mHandles = new ArrayList<UntypedHandle>(0);
267         }
268 
269         return result;
270     }
271 
272     /**
273      * @see ConsumerHandle#discardData(int, DataPipe.ReadFlags)
274      */
discardData(DataPipeConsumerHandleImpl handle, int numBytes, DataPipe.ReadFlags flags)275     int discardData(DataPipeConsumerHandleImpl handle, int numBytes, DataPipe.ReadFlags flags) {
276         ResultAnd<Integer> result = nativeReadData(handle.getMojoHandle(), null, numBytes,
277                 flags.getFlags() | MOJO_READ_DATA_FLAG_DISCARD);
278         if (result.getMojoResult() != MojoResult.OK) {
279             throw new MojoException(result.getMojoResult());
280         }
281         return result.getValue();
282     }
283 
284     /**
285      * @see ConsumerHandle#readData(ByteBuffer, DataPipe.ReadFlags)
286      */
readData( DataPipeConsumerHandleImpl handle, ByteBuffer elements, DataPipe.ReadFlags flags)287     ResultAnd<Integer> readData(
288             DataPipeConsumerHandleImpl handle, ByteBuffer elements, DataPipe.ReadFlags flags) {
289         ResultAnd<Integer> result = nativeReadData(handle.getMojoHandle(), elements,
290                 elements == null ? 0 : elements.capacity(), flags.getFlags());
291         if (result.getMojoResult() != MojoResult.OK
292                 && result.getMojoResult() != MojoResult.SHOULD_WAIT) {
293             throw new MojoException(result.getMojoResult());
294         }
295         if (result.getMojoResult() == MojoResult.OK) {
296             if (elements != null) {
297                 elements.limit(result.getValue());
298             }
299         }
300         return result;
301     }
302 
303     /**
304      * @see ConsumerHandle#beginReadData(int, DataPipe.ReadFlags)
305      */
beginReadData( DataPipeConsumerHandleImpl handle, int numBytes, DataPipe.ReadFlags flags)306     ByteBuffer beginReadData(
307             DataPipeConsumerHandleImpl handle, int numBytes, DataPipe.ReadFlags flags) {
308         ResultAnd<ByteBuffer> result =
309                 nativeBeginReadData(handle.getMojoHandle(), numBytes, flags.getFlags());
310         if (result.getMojoResult() != MojoResult.OK) {
311             throw new MojoException(result.getMojoResult());
312         }
313         return result.getValue().asReadOnlyBuffer();
314     }
315 
316     /**
317      * @see ConsumerHandle#endReadData(int)
318      */
endReadData(DataPipeConsumerHandleImpl handle, int numBytesRead)319     void endReadData(DataPipeConsumerHandleImpl handle, int numBytesRead) {
320         int result = nativeEndReadData(handle.getMojoHandle(), numBytesRead);
321         if (result != MojoResult.OK) {
322             throw new MojoException(result);
323         }
324     }
325 
326     /**
327      * @see ProducerHandle#writeData(ByteBuffer, DataPipe.WriteFlags)
328      */
writeData( DataPipeProducerHandleImpl handle, ByteBuffer elements, DataPipe.WriteFlags flags)329     ResultAnd<Integer> writeData(
330             DataPipeProducerHandleImpl handle, ByteBuffer elements, DataPipe.WriteFlags flags) {
331         return nativeWriteData(
332                 handle.getMojoHandle(), elements, elements.limit(), flags.getFlags());
333     }
334 
335     /**
336      * @see ProducerHandle#beginWriteData(int, DataPipe.WriteFlags)
337      */
beginWriteData( DataPipeProducerHandleImpl handle, int numBytes, DataPipe.WriteFlags flags)338     ByteBuffer beginWriteData(
339             DataPipeProducerHandleImpl handle, int numBytes, DataPipe.WriteFlags flags) {
340         ResultAnd<ByteBuffer> result =
341                 nativeBeginWriteData(handle.getMojoHandle(), numBytes, flags.getFlags());
342         if (result.getMojoResult() != MojoResult.OK) {
343             throw new MojoException(result.getMojoResult());
344         }
345         return result.getValue();
346     }
347 
348     /**
349      * @see ProducerHandle#endWriteData(int)
350      */
endWriteData(DataPipeProducerHandleImpl handle, int numBytesWritten)351     void endWriteData(DataPipeProducerHandleImpl handle, int numBytesWritten) {
352         int result = nativeEndWriteData(handle.getMojoHandle(), numBytesWritten);
353         if (result != MojoResult.OK) {
354             throw new MojoException(result);
355         }
356     }
357 
358     /**
359      * @see SharedBufferHandle#duplicate(DuplicateOptions)
360      */
duplicate(SharedBufferHandleImpl handle, DuplicateOptions options)361     SharedBufferHandle duplicate(SharedBufferHandleImpl handle, 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         ResultAnd<Integer> result = nativeDuplicate(handle.getMojoHandle(), optionsBuffer);
369         if (result.getMojoResult() != MojoResult.OK) {
370             throw new MojoException(result.getMojoResult());
371         }
372         return new SharedBufferHandleImpl(this, result.getValue());
373     }
374 
375     /**
376      * @see SharedBufferHandle#map(long, long, MapFlags)
377      */
map(SharedBufferHandleImpl handle, long offset, long numBytes, MapFlags flags)378     ByteBuffer map(SharedBufferHandleImpl handle, long offset, long numBytes, MapFlags flags) {
379         ResultAnd<ByteBuffer> result =
380                 nativeMap(handle.getMojoHandle(), offset, numBytes, flags.getFlags());
381         if (result.getMojoResult() != MojoResult.OK) {
382             throw new MojoException(result.getMojoResult());
383         }
384         return result.getValue();
385     }
386 
387     /**
388      * @see SharedBufferHandle#unmap(ByteBuffer)
389      */
unmap(ByteBuffer buffer)390     void unmap(ByteBuffer buffer) {
391         int result = nativeUnmap(buffer);
392         if (result != MojoResult.OK) {
393             throw new MojoException(result);
394         }
395     }
396 
397     /**
398      * @return the mojo handle associated to the given handle, considering invalid handles.
399      */
getMojoHandle(Handle handle)400     private int getMojoHandle(Handle handle) {
401         if (handle.isValid()) {
402             return ((HandleBase) handle).getMojoHandle();
403         }
404         return 0;
405     }
406 
isUnrecoverableError(int code)407     private static boolean isUnrecoverableError(int code) {
408         switch (code) {
409             case MojoResult.OK:
410             case MojoResult.DEADLINE_EXCEEDED:
411             case MojoResult.CANCELLED:
412             case MojoResult.FAILED_PRECONDITION:
413                 return false;
414             default:
415                 return true;
416         }
417     }
418 
filterMojoResultForWait(int code)419     private static int filterMojoResultForWait(int code) {
420         if (isUnrecoverableError(code)) {
421             throw new MojoException(code);
422         }
423         return code;
424     }
425 
allocateDirectBuffer(int capacity)426     private ByteBuffer allocateDirectBuffer(int capacity) {
427         ByteBuffer buffer = ByteBuffer.allocateDirect(capacity + mByteBufferOffset);
428         if (mByteBufferOffset != 0) {
429             buffer.position(mByteBufferOffset);
430             buffer = buffer.slice();
431         }
432         return buffer.order(ByteOrder.nativeOrder());
433     }
434 
435     @CalledByNative
newResultAndBuffer(int mojoResult, ByteBuffer buffer)436     private static ResultAnd<ByteBuffer> newResultAndBuffer(int mojoResult, ByteBuffer buffer) {
437         return new ResultAnd<>(mojoResult, buffer);
438     }
439 
440     /**
441      * Trivial alias for Pair<Integer, Integer>. This is needed because our jni generator is unable
442      * to handle class that contains space.
443      */
444     private static final class IntegerPair extends Pair<Integer, Integer> {
IntegerPair(Integer first, Integer second)445         public IntegerPair(Integer first, Integer second) {
446             super(first, second);
447         }
448     }
449 
450     @CalledByNative
newReadMessageResult( int mojoResult, byte[] data, int[] rawHandles)451     private static ResultAnd<MessagePipeHandle.ReadMessageResult> newReadMessageResult(
452             int mojoResult, byte[] data, int[] rawHandles) {
453         MessagePipeHandle.ReadMessageResult result = new MessagePipeHandle.ReadMessageResult();
454         if (mojoResult == MojoResult.OK) {
455             result.mData = data;
456             result.mRawHandles = rawHandles;
457         }
458         return new ResultAnd<>(mojoResult, result);
459     }
460 
461     @CalledByNative
newResultAndInteger(int mojoResult, int numBytesRead)462     private static ResultAnd<Integer> newResultAndInteger(int mojoResult, int numBytesRead) {
463         return new ResultAnd<>(mojoResult, numBytesRead);
464     }
465 
466     @CalledByNative
newNativeCreationResult( int mojoResult, int mojoHandle1, int mojoHandle2)467     private static ResultAnd<IntegerPair> newNativeCreationResult(
468             int mojoResult, int mojoHandle1, int mojoHandle2) {
469         return new ResultAnd<>(mojoResult, new IntegerPair(mojoHandle1, mojoHandle2));
470     }
471 
nativeGetTimeTicksNow()472     private native long nativeGetTimeTicksNow();
473 
nativeCreateMessagePipe(ByteBuffer optionsBuffer)474     private native ResultAnd<IntegerPair> nativeCreateMessagePipe(ByteBuffer optionsBuffer);
475 
nativeCreateDataPipe(ByteBuffer optionsBuffer)476     private native ResultAnd<IntegerPair> nativeCreateDataPipe(ByteBuffer optionsBuffer);
477 
nativeCreateSharedBuffer( ByteBuffer optionsBuffer, long numBytes)478     private native ResultAnd<Integer> nativeCreateSharedBuffer(
479             ByteBuffer optionsBuffer, long numBytes);
480 
nativeClose(int mojoHandle)481     private native int nativeClose(int mojoHandle);
482 
nativeQueryHandleSignalsState(int mojoHandle, ByteBuffer signalsStateBuffer)483     private native int nativeQueryHandleSignalsState(int mojoHandle, ByteBuffer signalsStateBuffer);
484 
nativeWriteMessage( int mojoHandle, ByteBuffer bytes, int numBytes, ByteBuffer handlesBuffer, int flags)485     private native int nativeWriteMessage(
486             int mojoHandle, ByteBuffer bytes, int numBytes, ByteBuffer handlesBuffer, int flags);
487 
nativeReadMessage( int mojoHandle, int flags)488     private native ResultAnd<MessagePipeHandle.ReadMessageResult> nativeReadMessage(
489             int mojoHandle, int flags);
490 
nativeReadData( int mojoHandle, ByteBuffer elements, int elementsSize, int flags)491     private native ResultAnd<Integer> nativeReadData(
492             int mojoHandle, ByteBuffer elements, int elementsSize, int flags);
493 
nativeBeginReadData( int mojoHandle, int numBytes, int flags)494     private native ResultAnd<ByteBuffer> nativeBeginReadData(
495             int mojoHandle, int numBytes, int flags);
496 
nativeEndReadData(int mojoHandle, int numBytesRead)497     private native int nativeEndReadData(int mojoHandle, int numBytesRead);
498 
nativeWriteData( int mojoHandle, ByteBuffer elements, int limit, int flags)499     private native ResultAnd<Integer> nativeWriteData(
500             int mojoHandle, ByteBuffer elements, int limit, int flags);
501 
nativeBeginWriteData( int mojoHandle, int numBytes, int flags)502     private native ResultAnd<ByteBuffer> nativeBeginWriteData(
503             int mojoHandle, int numBytes, int flags);
504 
nativeEndWriteData(int mojoHandle, int numBytesWritten)505     private native int nativeEndWriteData(int mojoHandle, int numBytesWritten);
506 
nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer)507     private native ResultAnd<Integer> nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer);
508 
nativeMap( int mojoHandle, long offset, long numBytes, int flags)509     private native ResultAnd<ByteBuffer> nativeMap(
510             int mojoHandle, long offset, long numBytes, int flags);
511 
nativeUnmap(ByteBuffer buffer)512     private native int nativeUnmap(ByteBuffer buffer);
513 
nativeGetNativeBufferOffset(ByteBuffer buffer, int alignment)514     private native int nativeGetNativeBufferOffset(ByteBuffer buffer, int alignment);
515 }
516