diff options
author | qsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-20 15:36:34 +0000 |
---|---|---|
committer | qsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-20 15:36:34 +0000 |
commit | 7d9d82e1b08b031b24451d6cb7f035d0cc3f7365 (patch) | |
tree | e879929a8d6574a0d5c7f1b2fc862f053d263295 | |
parent | 07177bac1c498f5f3e8307058dd8a36ca02b1756 (diff) | |
download | chromium_src-7d9d82e1b08b031b24451d6cb7f035d0cc3f7365.zip chromium_src-7d9d82e1b08b031b24451d6cb7f035d0cc3f7365.tar.gz chromium_src-7d9d82e1b08b031b24451d6cb7f035d0cc3f7365.tar.bz2 |
Add AsyncWaiter implementation to java API.
Review URL: https://codereview.chromium.org/288993002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271660 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | mojo/android/javatests/core_test.cc | 35 | ||||
-rw-r--r-- | mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java | 307 | ||||
-rw-r--r-- | mojo/android/system/core_impl.cc | 82 | ||||
-rw-r--r-- | mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java | 106 | ||||
-rw-r--r-- | mojo/mojo.gyp | 1 | ||||
-rw-r--r-- | mojo/public/java/src/org/chromium/mojo/system/AsyncWaiter.java | 53 | ||||
-rw-r--r-- | mojo/public/java/src/org/chromium/mojo/system/Core.java | 6 |
7 files changed, 582 insertions, 8 deletions
diff --git a/mojo/android/javatests/core_test.cc b/mojo/android/javatests/core_test.cc index 3d4032f..38aa6c4 100644 --- a/mojo/android/javatests/core_test.cc +++ b/mojo/android/javatests/core_test.cc @@ -6,7 +6,22 @@ #include "base/android/jni_android.h" #include "base/android/scoped_java_ref.h" +#include "base/bind.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/test/test_support_android.h" #include "jni/CoreTest_jni.h" +#include "mojo/public/cpp/environment/environment.h" + +namespace { + +struct TestEnvironment { + mojo::Environment environment; + base::MessageLoopForUI message_loop; +}; + +} // namespace namespace mojo { namespace android { @@ -16,6 +31,26 @@ static void InitApplicationContext(JNIEnv* env, jobject context) { base::android::ScopedJavaLocalRef<jobject> scoped_context(env, context); base::android::InitApplicationContext(env, scoped_context); + base::InitAndroidTestMessageLoop(); +} + +static jlong SetupTestEnvironment(JNIEnv* env, jobject jcaller) { + return reinterpret_cast<intptr_t>(new TestEnvironment()); +} + +static void TearDownTestEnvironment(JNIEnv* env, + jobject jcaller, + jlong test_environment) { + delete reinterpret_cast<TestEnvironment*>(test_environment); +} + +static void RunLoop(JNIEnv* env, jobject jcaller, jlong timeout_ms) { + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::MessageLoop::QuitClosure(), + base::TimeDelta::FromMilliseconds(timeout_ms)); + base::RunLoop run_loop; + run_loop.Run(); } bool RegisterCoreTest(JNIEnv* env) { diff --git a/mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java b/mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java index bf941b0..b534752 100644 --- a/mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java +++ b/mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java @@ -10,6 +10,8 @@ import android.test.suitebuilder.annotation.SmallTest; import org.chromium.base.JNINamespace; import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.mojo.system.AsyncWaiter.Callback; +import org.chromium.mojo.system.AsyncWaiter.Cancellable; import org.chromium.mojo.system.Core.WaitFlags; import org.chromium.mojo.system.Core.WaitManyResult; import org.chromium.mojo.system.MessagePipeHandle.ReadFlags; @@ -33,16 +35,31 @@ import java.util.concurrent.TimeUnit; @JNINamespace("mojo::android") public class CoreTest extends InstrumentationTestCase { + private static final long RUN_LOOP_TIMEOUT_MS = 5; + private static final ScheduledExecutorService WORKER = Executors.newSingleThreadScheduledExecutor(); + private long mTestEnvironmentPointer; + /** * @see junit.framework.TestCase#setUp() */ @Override protected void setUp() throws Exception { + super.setUp(); LibraryLoader.ensureInitialized(); nativeInitApplicationContext(getInstrumentation().getTargetContext()); + mTestEnvironmentPointer = nativeSetupTestEnvironment(); + } + + /** + * @see android.test.InstrumentationTestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + nativeTearDownTestEnvironment(mTestEnvironmentPointer); + super.tearDown(); } /** @@ -518,5 +535,295 @@ public class CoreTest extends InstrumentationTestCase { } } + private static class AsyncWaiterResult implements Callback { + private int mResult = Integer.MIN_VALUE; + private MojoException mException = null; + + /** + * @see Callback#onResult(int) + */ + @Override + public void onResult(int result) { + this.mResult = result; + } + + /** + * @see Callback#onError(MojoException) + */ + @Override + public void onError(MojoException exception) { + this.mException = exception; + } + + /** + * @return the result + */ + public int getResult() { + return mResult; + } + + /** + * @return the exception + */ + public MojoException getException() { + return mException; + } + + } + + /** + * Testing core {@link AsyncWaiter} implementation. + */ + @SmallTest + public void testAsyncWaiterCorrectResult() { + Core core = CoreImpl.getInstance(); + + // Checking a correct result. + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + try { + final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + core.getDefaultAsyncWaiter().asyncWait(handles.first, + WaitFlags.none().setReadable(true), Core.DEADLINE_INFINITE, asyncWaiterResult); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + handles.second.writeMessage(ByteBuffer.allocateDirect(1), null, + MessagePipeHandle.WriteFlags.none()); + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertNull(asyncWaiterResult.getException()); + assertEquals(MojoResult.OK, asyncWaiterResult.getResult()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing core {@link AsyncWaiter} implementation. + */ + @SmallTest + public void testAsyncWaiterClosingPeerHandle() { + Core core = CoreImpl.getInstance(); + + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + try { + final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + core.getDefaultAsyncWaiter().asyncWait(handles.first, + WaitFlags.none().setReadable(true), Core.DEADLINE_INFINITE, asyncWaiterResult); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + handles.second.close(); + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertNull(asyncWaiterResult.getException()); + assertEquals(MojoResult.FAILED_PRECONDITION, asyncWaiterResult.getResult()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing core {@link AsyncWaiter} implementation. + */ + @SmallTest + public void testAsyncWaiterClosingWaitingHandle() { + Core core = CoreImpl.getInstance(); + + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + try { + final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + core.getDefaultAsyncWaiter().asyncWait(handles.first, + WaitFlags.none().setReadable(true), Core.DEADLINE_INFINITE, asyncWaiterResult); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + handles.first.close(); + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + // TODO(qsr) Re-enable when MojoWaitMany handles it correctly. + // assertNull(asyncWaiterResult.getException()); + // assertEquals(MojoResult.CANCELLED, asyncWaiterResult.getResult()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing core {@link AsyncWaiter} implementation. + */ + @SmallTest + public void testAsyncWaiterWaitingOnInvalidHandle() { + Core core = CoreImpl.getInstance(); + + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + try { + final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + handles.first.close(); + core.getDefaultAsyncWaiter().asyncWait(handles.first, + WaitFlags.none().setReadable(true), Core.DEADLINE_INFINITE, asyncWaiterResult); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertNotNull(asyncWaiterResult.getException()); + assertEquals(MojoResult.INVALID_ARGUMENT, + asyncWaiterResult.getException().getMojoResult()); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing core {@link AsyncWaiter} implementation. + */ + @SmallTest + public void testAsyncWaiterWaitingOnDefaultInvalidHandle() { + Core core = CoreImpl.getInstance(); + + final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + core.getDefaultAsyncWaiter().asyncWait(new InvalidHandle(), + WaitFlags.none().setReadable(true), Core.DEADLINE_INFINITE, asyncWaiterResult); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertNotNull(asyncWaiterResult.getException()); + assertEquals(MojoResult.INVALID_ARGUMENT, + asyncWaiterResult.getException().getMojoResult()); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + } + + /** + * Testing core {@link AsyncWaiter} implementation. + */ + @SmallTest + public void testAsyncWaiterWaitingWithTimeout() { + Core core = CoreImpl.getInstance(); + + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + try { + final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + core.getDefaultAsyncWaiter().asyncWait(handles.first, + WaitFlags.none().setReadable(true), RUN_LOOP_TIMEOUT_MS, asyncWaiterResult); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + nativeRunLoop(10 * RUN_LOOP_TIMEOUT_MS); + assertNull(asyncWaiterResult.getException()); + assertEquals(MojoResult.DEADLINE_EXCEEDED, asyncWaiterResult.getResult()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing core {@link AsyncWaiter} implementation. + */ + @SmallTest + public void testAsyncWaiterCancelWaiting() { + Core core = CoreImpl.getInstance(); + + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + try { + final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + Cancellable cancellable = core.getDefaultAsyncWaiter().asyncWait(handles.first, + WaitFlags.none().setReadable(true), Core.DEADLINE_INFINITE, asyncWaiterResult); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + cancellable.cancel(); + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + handles.second.writeMessage(ByteBuffer.allocateDirect(1), null, + MessagePipeHandle.WriteFlags.none()); + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing core {@link AsyncWaiter} implementation. + */ + @SmallTest + public void testAsyncWaiterImmediateCancelOnInvalidHandle() { + Core core = CoreImpl.getInstance(); + + // Closing the peer handle. + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + try { + final AsyncWaiterResult asyncWaiterResult = new AsyncWaiterResult(); + handles.first.close(); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + + Cancellable cancellable = core.getDefaultAsyncWaiter().asyncWait(handles.first, + WaitFlags.none().setReadable(true), Core.DEADLINE_INFINITE, asyncWaiterResult); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + cancellable.cancel(); + + nativeRunLoop(RUN_LOOP_TIMEOUT_MS); + assertEquals(Integer.MIN_VALUE, asyncWaiterResult.getResult()); + assertEquals(null, asyncWaiterResult.getException()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + private native void nativeInitApplicationContext(Context context); + + private native long nativeSetupTestEnvironment(); + + private native void nativeTearDownTestEnvironment(long testEnvironment); + + private native void nativeRunLoop(long timeoutMS); } diff --git a/mojo/android/system/core_impl.cc b/mojo/android/system/core_impl.cc index d7552c1..34d009c 100644 --- a/mojo/android/system/core_impl.cc +++ b/mojo/android/system/core_impl.cc @@ -8,10 +8,43 @@ #include "base/android/jni_android.h" #include "base/android/jni_registrar.h" #include "base/android/library_loader/library_loader_hooks.h" -#include "base/logging.h" +#include "base/android/scoped_java_ref.h" +#include "base/bind.h" +#include "base/message_loop/message_loop.h" #include "jni/CoreImpl_jni.h" #include "mojo/embedder/embedder.h" +#include "mojo/public/c/environment/async_waiter.h" #include "mojo/public/c/system/core.h" +#include "mojo/public/cpp/environment/default_async_waiter.h" + +namespace { + +// |AsyncWait| is guaranteed never to return 0. +const MojoAsyncWaitID kInvalidHandleCancelID = 0; + +struct AsyncWaitCallbackData { + base::android::ScopedJavaGlobalRef<jobject> core_impl; + base::android::ScopedJavaGlobalRef<jobject> callback; + base::android::ScopedJavaGlobalRef<jobject> cancellable; + + AsyncWaitCallbackData(JNIEnv* env, jobject core_impl, jobject callback) { + this->core_impl.Reset(env, core_impl); + this->callback.Reset(env, callback); + } +}; + +void AsyncWaitCallback(void* data, MojoResult result) { + scoped_ptr<AsyncWaitCallbackData> callback_data( + static_cast<AsyncWaitCallbackData*>(data)); + mojo::android::Java_CoreImpl_onAsyncWaitResult( + base::android::AttachCurrentThread(), + callback_data->core_impl.obj(), + result, + callback_data->callback.obj(), + callback_data->cancellable.obj()); +} + +} // namespace namespace mojo { namespace android { @@ -285,6 +318,53 @@ static int Unmap(JNIEnv* env, jobject jcaller, jobject buffer) { return MojoUnmapBuffer(buffer_start); } +static jobject AsyncWait(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jint flags, + jlong deadline, + jobject callback) { + AsyncWaitCallbackData* callback_data = + new AsyncWaitCallbackData(env, jcaller, callback); + MojoAsyncWaitID cancel_id; + if (static_cast<MojoHandle>(mojo_handle) != MOJO_HANDLE_INVALID) { + MojoAsyncWaiter* async_waiter = mojo::GetDefaultAsyncWaiter(); + cancel_id = async_waiter->AsyncWait(async_waiter, + mojo_handle, + flags, + deadline, + AsyncWaitCallback, + callback_data); + } else { + cancel_id = kInvalidHandleCancelID; + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind( + &AsyncWaitCallback, callback_data, MOJO_RESULT_INVALID_ARGUMENT)); + } + base::android::ScopedJavaLocalRef<jobject> cancellable = + Java_CoreImpl_newAsyncWaiterCancellableImpl( + env, jcaller, cancel_id, reinterpret_cast<intptr_t>(callback_data)); + callback_data->cancellable.Reset(env, cancellable.obj()); + return cancellable.Release(); +} + +static void CancelAsyncWait(JNIEnv* env, + jobject jcaller, + jlong id, + jlong data_ptr) { + if (id == 0) { + // If |id| is |kInvalidHandleCancelID|, the async wait was done on an + // invalid handle, so the AsyncWaitCallback will be called and will clear + // the data_ptr. + return; + } + scoped_ptr<AsyncWaitCallbackData> deleter( + reinterpret_cast<AsyncWaitCallbackData*>(data_ptr)); + MojoAsyncWaiter* async_waiter = mojo::GetDefaultAsyncWaiter(); + async_waiter->CancelWait(async_waiter, id); +} + bool RegisterCoreImpl(JNIEnv* env) { return RegisterNativesImpl(env); } diff --git a/mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java b/mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java index cd6cee5..39d17f4 100644 --- a/mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java +++ b/mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java @@ -5,6 +5,7 @@ package org.chromium.mojo.system; import org.chromium.base.CalledByNative; +import org.chromium.base.JNIAdditionalImport; import org.chromium.base.JNINamespace; import org.chromium.mojo.system.DataPipe.ConsumerHandle; import org.chromium.mojo.system.DataPipe.ProducerHandle; @@ -19,8 +20,9 @@ import java.util.List; /** * Implementation of {@link Core}. */ +@JNIAdditionalImport(AsyncWaiter.class) @JNINamespace("mojo::android") -public class CoreImpl implements Core { +public class CoreImpl implements Core, AsyncWaiter { /** * Discard flag for the |MojoReadData| operation. @@ -154,6 +156,24 @@ public class CoreImpl implements Core { return new SharedBufferHandleImpl(this, result.getMojoHandle1()); } + /** + * @see Core#getDefaultAsyncWaiter() + */ + @Override + public AsyncWaiter getDefaultAsyncWaiter() { + return this; + } + + /** + * @see AsyncWaiter#asyncWait(Handle, Core.WaitFlags, long, Callback) + */ + @Override + public Cancellable asyncWait(Handle handle, WaitFlags flags, long deadline, + Callback callback) { + return nativeAsyncWait(getMojoHandle(handle), + flags.getFlags(), deadline, callback); + } + int closeWithResult(int mojoHandle) { return nativeClose(mojoHandle); } @@ -372,19 +392,31 @@ public class CoreImpl implements Core { return 0; } - private static int filterMojoResultForWait(int code) { - if (code >= 0) { - return MojoResult.OK; - } + private static boolean isUnrecoverableError(int code) { switch (code) { + case MojoResult.OK: case MojoResult.DEADLINE_EXCEEDED: case MojoResult.CANCELLED: case MojoResult.FAILED_PRECONDITION: - return code; + return false; default: - throw new MojoException(code); + return true; + } + } + + private static int filterMojoResult(int code) { + if (code >= 0) { + return MojoResult.OK; } + return code; + } + private static int filterMojoResultForWait(int code) { + int finalCode = filterMojoResult(code); + if (isUnrecoverableError(finalCode)) { + throw new MojoException(finalCode); + } + return finalCode; } private static ByteBuffer allocateDirectBuffer(int capacity) { @@ -427,6 +459,62 @@ public class CoreImpl implements Core { } + /** + * Implementation of {@link AsyncWaiter.Cancellable}. + */ + private class AsyncWaiterCancellableImpl implements AsyncWaiter.Cancellable { + + private final long mId; + private final long mDataPtr; + private boolean mActive = true; + + private AsyncWaiterCancellableImpl(long id, long dataPtr) { + this.mId = id; + this.mDataPtr = dataPtr; + } + + /** + * @see AsyncWaiter.Cancellable#cancel() + */ + @Override + public void cancel() { + if (mActive) { + mActive = false; + nativeCancelAsyncWait(mId, mDataPtr); + } + } + + private boolean isActive() { + return mActive; + } + + private void deactivate() { + mActive = false; + } + } + + @CalledByNative + private AsyncWaiterCancellableImpl newAsyncWaiterCancellableImpl(long id, long dataPtr) { + return new AsyncWaiterCancellableImpl(id, dataPtr); + } + + @CalledByNative + private void onAsyncWaitResult(int mojoResult, + AsyncWaiter.Callback callback, + AsyncWaiterCancellableImpl cancellable) { + if (!cancellable.isActive()) { + // If cancellable is not active, the user cancelled the wait. + return; + } + cancellable.deactivate(); + int finalCode = filterMojoResult(mojoResult); + if (isUnrecoverableError(finalCode)) { + callback.onError(new MojoException(finalCode)); + return; + } + callback.onResult(finalCode); + } + @CalledByNative private static NativeCodeAndBufferResult newNativeCodeAndBufferResult(int mojoResult, ByteBuffer buffer) { @@ -592,4 +680,8 @@ public class CoreImpl implements Core { private native int nativeUnmap(ByteBuffer buffer); + private native AsyncWaiterCancellableImpl nativeAsyncWait(int mojoHandle, int flags, + long deadline, AsyncWaiter.Callback callback); + + private native void nativeCancelAsyncWait(long mId, long dataPtr); } diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index 9d0b02c..5c9198f 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -725,6 +725,7 @@ 'type': 'shared_library', 'dependencies': [ '../base/base.gyp:base', + '../base/base.gyp:test_support_base', 'libmojo_system_java', 'mojo_jni_headers', ], diff --git a/mojo/public/java/src/org/chromium/mojo/system/AsyncWaiter.java b/mojo/public/java/src/org/chromium/mojo/system/AsyncWaiter.java new file mode 100644 index 0000000..f62ac76 --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/AsyncWaiter.java @@ -0,0 +1,53 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.mojo.system; + +import org.chromium.mojo.system.Core.WaitFlags; + +/** + * A class which implements the {@link AsyncWaiter} allows asynchronously waiting on a background + * thread. + */ +public interface AsyncWaiter { + + /** + * Allows cancellation of an asyncWait operation. + */ + interface Cancellable { + /** + * Cancels an asyncWait operation. Has no effect if the operation has already been canceled + * or the callback has already been called. + * <p> + * Must be called from the same thread as {@link AsyncWaiter#asyncWait} was called from. + */ + void cancel(); + } + + /** + * Callback passed to {@link AsyncWaiter#asyncWait}. + */ + public interface Callback { + /** + * Called when the handle is ready. + */ + public void onResult(int result); + + /** + * Called when an error occurred while waiting. + */ + public void onError(MojoException exception); + } + + /** + * Asynchronously call wait on a background thread. The given {@link Callback} will be notified + * of the result of the wait on the same thread as asyncWait was called. + * + * @return a {@link Cancellable} object that can be used to cancel waiting. The cancellable + * should only be used on the current thread, and becomes invalid once the callback has + * been notified. + */ + Cancellable asyncWait(Handle handle, WaitFlags flags, long deadline, Callback callback); + +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/Core.java b/mojo/public/java/src/org/chromium/mojo/system/Core.java index 8d084b3..02b6618 100644 --- a/mojo/public/java/src/org/chromium/mojo/system/Core.java +++ b/mojo/public/java/src/org/chromium/mojo/system/Core.java @@ -175,4 +175,10 @@ public interface Core { */ public SharedBufferHandle createSharedBuffer(SharedBufferHandle.CreateOptions options, long numBytes); + + /** + * Returns a default implementation of {@link AsyncWaiter}. + */ + public AsyncWaiter getDefaultAsyncWaiter(); + } |