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