Home | History | Annotate | Download | only in impl
      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      */
     74     public static Core getInstance() {
     75         return LazyHolder.INSTANCE;
     76     }
     77 
     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
     89     public long getTimeTicksNow() {
     90         return nativeGetTimeTicksNow();
     91     }
     92 
     93     /**
     94      * @see Core#createMessagePipe(MessagePipeHandle.CreateOptions)
     95      */
     96     @Override
     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
    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
    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
    159     public UntypedHandle acquireNativeHandle(int handle) {
    160         return new UntypedHandleImpl(this, handle);
    161     }
    162 
    163     /**
    164      * @see Core#getWatcher()
    165      */
    166     @Override
    167     public Watcher getWatcher() {
    168         return new WatcherImpl();
    169     }
    170 
    171     /**
    172      * @see Core#createDefaultRunLoop()
    173      */
    174     @Override
    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
    188     public RunLoop getCurrentRunLoop() {
    189         return mCurrentRunLoop.get();
    190     }
    191 
    192     /**
    193      * Remove the current run loop.
    194      */
    195     void clearCurrentRunLoop() {
    196         mCurrentRunLoop.remove();
    197     }
    198 
    199     int closeWithResult(int mojoHandle) {
    200         return nativeClose(mojoHandle);
    201     }
    202 
    203     void close(int mojoHandle) {
    204         int mojoResult = nativeClose(mojoHandle);
    205         if (mojoResult != MojoResult.OK) {
    206             throw new MojoException(mojoResult);
    207         }
    208     }
    209 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    400     private int getMojoHandle(Handle handle) {
    401         if (handle.isValid()) {
    402             return ((HandleBase) handle).getMojoHandle();
    403         }
    404         return 0;
    405     }
    406 
    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 
    419     private static int filterMojoResultForWait(int code) {
    420         if (isUnrecoverableError(code)) {
    421             throw new MojoException(code);
    422         }
    423         return code;
    424     }
    425 
    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
    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> {
    445         public IntegerPair(Integer first, Integer second) {
    446             super(first, second);
    447         }
    448     }
    449 
    450     @CalledByNative
    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
    462     private static ResultAnd<Integer> newResultAndInteger(int mojoResult, int numBytesRead) {
    463         return new ResultAnd<>(mojoResult, numBytesRead);
    464     }
    465 
    466     @CalledByNative
    467     private static ResultAnd<IntegerPair> newNativeCreationResult(
    468             int mojoResult, int mojoHandle1, int mojoHandle2) {
    469         return new ResultAnd<>(mojoResult, new IntegerPair(mojoHandle1, mojoHandle2));
    470     }
    471 
    472     private native long nativeGetTimeTicksNow();
    473 
    474     private native ResultAnd<IntegerPair> nativeCreateMessagePipe(ByteBuffer optionsBuffer);
    475 
    476     private native ResultAnd<IntegerPair> nativeCreateDataPipe(ByteBuffer optionsBuffer);
    477 
    478     private native ResultAnd<Integer> nativeCreateSharedBuffer(
    479             ByteBuffer optionsBuffer, long numBytes);
    480 
    481     private native int nativeClose(int mojoHandle);
    482 
    483     private native int nativeQueryHandleSignalsState(int mojoHandle, ByteBuffer signalsStateBuffer);
    484 
    485     private native int nativeWriteMessage(
    486             int mojoHandle, ByteBuffer bytes, int numBytes, ByteBuffer handlesBuffer, int flags);
    487 
    488     private native ResultAnd<MessagePipeHandle.ReadMessageResult> nativeReadMessage(
    489             int mojoHandle, int flags);
    490 
    491     private native ResultAnd<Integer> nativeReadData(
    492             int mojoHandle, ByteBuffer elements, int elementsSize, int flags);
    493 
    494     private native ResultAnd<ByteBuffer> nativeBeginReadData(
    495             int mojoHandle, int numBytes, int flags);
    496 
    497     private native int nativeEndReadData(int mojoHandle, int numBytesRead);
    498 
    499     private native ResultAnd<Integer> nativeWriteData(
    500             int mojoHandle, ByteBuffer elements, int limit, int flags);
    501 
    502     private native ResultAnd<ByteBuffer> nativeBeginWriteData(
    503             int mojoHandle, int numBytes, int flags);
    504 
    505     private native int nativeEndWriteData(int mojoHandle, int numBytesWritten);
    506 
    507     private native ResultAnd<Integer> nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer);
    508 
    509     private native ResultAnd<ByteBuffer> nativeMap(
    510             int mojoHandle, long offset, long numBytes, int flags);
    511 
    512     private native int nativeUnmap(ByteBuffer buffer);
    513 
    514     private native int nativeGetNativeBufferOffset(ByteBuffer buffer, int alignment);
    515 }
    516