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