Commit 7d9d82e1 authored by qsr@chromium.org's avatar qsr@chromium.org

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
parent 07177bac
......@@ -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) {
......
......@@ -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);
}
......
......@@ -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);
}
......@@ -725,6 +725,7 @@
'type': 'shared_library',
'dependencies': [
'../base/base.gyp:base',
'../base/base.gyp:test_support_base',
'libmojo_system_java',
'mojo_jni_headers',
],
......
// 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);
}
......@@ -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();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment