diff options
author | qsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-23 16:02:32 +0000 |
---|---|---|
committer | qsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-23 16:02:32 +0000 |
commit | 70c0364a44341bf10c5157c11d3689a3cf7c6054 (patch) | |
tree | 201dff677afe4bb771b89f370a4c93ee5e276305 /mojo | |
parent | 76b34ffc13b9d895f60e20a752f5d09317d00db0 (diff) | |
download | chromium_src-70c0364a44341bf10c5157c11d3689a3cf7c6054.zip chromium_src-70c0364a44341bf10c5157c11d3689a3cf7c6054.tar.gz chromium_src-70c0364a44341bf10c5157c11d3689a3cf7c6054.tar.bz2 |
Java API for mojo system.
This CL introduce the java API for mojo system. It also introduces the android
implementation of this API.
Review URL: https://codereview.chromium.org/228723002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@265658 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo')
29 files changed, 3087 insertions, 15 deletions
diff --git a/mojo/android/DEPS b/mojo/android/DEPS new file mode 100644 index 0000000..c80012b5 --- /dev/null +++ b/mojo/android/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+jni", +] diff --git a/mojo/android/javatests/AndroidManifest.xml b/mojo/android/javatests/AndroidManifest.xml new file mode 100644 index 0000000..8968941 --- /dev/null +++ b/mojo/android/javatests/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> + <!-- Copyright (c) 2012 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 name must be unique so suffix with "tests" so package loader + doesn't ignore this. --> + <manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.chromium.mojo.tests"> + <!-- We add an application tag here just so that we can indicate that this + package needs to link against the android.test library, which is + needed when building test cases. --> + <application> + <uses-library android:name="android.test.runner" /> + </application> + <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="org.chromium.mojo.tests" + android:label="Tests for org.chromium.mojo"/> + <uses-permission android:name="android.permission.RUN_INSTRUMENTATION" /> + <uses-permission android:name="android.permission.INJECT_EVENTS" /> +</manifest> diff --git a/mojo/android/javatests/apk/EMPTY b/mojo/android/javatests/apk/EMPTY new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mojo/android/javatests/apk/EMPTY diff --git a/mojo/android/javatests/core_test.cc b/mojo/android/javatests/core_test.cc new file mode 100644 index 0000000..3d4032f --- /dev/null +++ b/mojo/android/javatests/core_test.cc @@ -0,0 +1,26 @@ +// 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. + +#include "mojo/android/javatests/core_test.h" + +#include "base/android/jni_android.h" +#include "base/android/scoped_java_ref.h" +#include "jni/CoreTest_jni.h" + +namespace mojo { +namespace android { + +static void InitApplicationContext(JNIEnv* env, + jobject jcaller, + jobject context) { + base::android::ScopedJavaLocalRef<jobject> scoped_context(env, context); + base::android::InitApplicationContext(env, scoped_context); +} + +bool RegisterCoreTest(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android +} // namespace mojo diff --git a/mojo/android/javatests/core_test.h b/mojo/android/javatests/core_test.h new file mode 100644 index 0000000..96c8878 --- /dev/null +++ b/mojo/android/javatests/core_test.h @@ -0,0 +1,20 @@ +// 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. + +#ifndef MOJO_ANDROID_JAVATESTS_CORE_TEST_H_ +#define MOJO_ANDROID_JAVATESTS_CORE_TEST_H_ + +#include <jni.h> + +#include "base/android/jni_android.h" + +namespace mojo { +namespace android { + +JNI_EXPORT bool RegisterCoreTest(JNIEnv* env); + +} // namespace android +} // namespace mojo + +#endif // MOJO_SYSTEM_ANDROID_JAVATESTS_CORE_TEST_H_ diff --git a/mojo/android/javatests/init_library.cc b/mojo/android/javatests/init_library.cc new file mode 100644 index 0000000..7b4cbe3 --- /dev/null +++ b/mojo/android/javatests/init_library.cc @@ -0,0 +1,40 @@ +// 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. + +#include "base/android/base_jni_registrar.h" +#include "base/android/jni_android.h" +#include "base/android/jni_registrar.h" +#include "base/android/library_loader/library_loader_hooks.h" +#include "mojo/android/javatests/core_test.h" +#include "mojo/android/system/core_impl.h" + +namespace { + +base::android::RegistrationMethod kMojoRegisteredMethods[] = { + { "CoreImpl", mojo::android::RegisterCoreImpl }, + { "CoreTest", mojo::android::RegisterCoreTest }, +}; + +bool RegisterMojoJni(JNIEnv* env) { + return RegisterNativeMethods(env, kMojoRegisteredMethods, + arraysize(kMojoRegisteredMethods)); +} + +} // namespace + +JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { + base::android::InitVM(vm); + JNIEnv* env = base::android::AttachCurrentThread(); + + if (!base::android::RegisterLibraryLoaderEntryHook(env)) + return -1; + + if (!base::android::RegisterJni(env)) + return -1; + + if (!RegisterMojoJni(env)) + return -1; + + return JNI_VERSION_1_4; +} diff --git a/mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java b/mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java new file mode 100644 index 0000000..97f0912 --- /dev/null +++ b/mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java @@ -0,0 +1,471 @@ +// 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 android.content.Context; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.base.JNINamespace; +import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.mojo.system.Core.WaitFlags; +import org.chromium.mojo.system.Core.WaitManyResult; +import org.chromium.mojo.system.MessagePipeHandle.ReadFlags; +import org.chromium.mojo.system.MessagePipeHandle.ReadMessageResult; +import org.chromium.mojo.system.MessagePipeHandle.WriteFlags; +import org.chromium.mojo.system.SharedBufferHandle.MapFlags; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * Testing the core API. + */ +@JNINamespace("mojo::android") +public class CoreTest extends InstrumentationTestCase { + + private static final ScheduledExecutorService WORKER = + Executors.newSingleThreadScheduledExecutor(); + + /** + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + LibraryLoader.ensureInitialized(); + nativeInitApplicationContext(getInstrumentation().getTargetContext()); + } + + /** + * Runnable that will close the given handle. + */ + private static class CloseHandle implements Runnable { + private Handle mHandle; + + CloseHandle(Handle handle) { + mHandle = handle; + } + + @Override + public void run() { + mHandle.close(); + } + } + + private static void checkSendingMessage(MessagePipeHandle in, MessagePipeHandle out) { + Random random = new Random(); + + // Writing a random 8 bytes message. + byte[] bytes = new byte[8]; + random.nextBytes(bytes); + ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length); + buffer.put(bytes); + in.writeMessage(buffer, null, MessagePipeHandle.WriteFlags.none()); + + // Try to read into a small buffer. + ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length / 2); + MessagePipeHandle.ReadMessageResult result = out.readMessage(receiveBuffer, 0, + MessagePipeHandle.ReadFlags.none()); + assertFalse(result.getWasMessageRead()); + assertEquals(bytes.length, result.getMessageSize()); + assertEquals(0, result.getHandlesCount()); + + // Read into a correct buffer. + receiveBuffer = ByteBuffer.allocateDirect(bytes.length); + result = out.readMessage(receiveBuffer, 0, + MessagePipeHandle.ReadFlags.none()); + assertTrue(result.getWasMessageRead()); + assertEquals(bytes.length, result.getMessageSize()); + assertEquals(0, result.getHandlesCount()); + assertEquals(0, receiveBuffer.position()); + assertEquals(result.getMessageSize(), receiveBuffer.limit()); + byte[] receivedBytes = new byte[result.getMessageSize()]; + receiveBuffer.get(receivedBytes); + assertTrue(Arrays.equals(bytes, receivedBytes)); + + } + + /** + * Testing {@link Core#waitMany(List, long)}. + */ + @SmallTest + public void testWaitMany() { + Core core = CoreSingleton.getInstance(); + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + + try { + List<Pair<Handle, WaitFlags>> handlesToWaitOn = new ArrayList< + Pair<Handle, WaitFlags>>(); + + handlesToWaitOn.add( + new Pair<Handle, WaitFlags>(handles.second, + WaitFlags.none().setReadable(true))); + handlesToWaitOn.add( + new Pair<Handle, WaitFlags>(handles.first, WaitFlags.none().setWritable(true))); + WaitManyResult result = core.waitMany(handlesToWaitOn, 0); + assertEquals(MojoResult.OK, result.getMojoResult()); + assertEquals(1, result.getHandleIndex()); + + handlesToWaitOn.clear(); + handlesToWaitOn.add( + new Pair<Handle, WaitFlags>(handles.first, WaitFlags.none().setWritable(true))); + handlesToWaitOn.add( + new Pair<Handle, WaitFlags>(handles.second, + WaitFlags.none().setReadable(true))); + result = core.waitMany(handlesToWaitOn, 0); + assertEquals(MojoResult.OK, result.getMojoResult()); + assertEquals(0, result.getHandleIndex()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing {@link MessagePipeHandle}. + */ + @SmallTest + public void testMessagePipeEmpty() { + Core core = CoreSingleton.getInstance(); + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + + try { + // Testing wait. + assertEquals(MojoResult.OK, handles.first.wait(WaitFlags.all(), 0)); + assertEquals(MojoResult.OK, handles.first.wait(WaitFlags.none().setWritable(true), 0)); + assertEquals(MojoResult.DEADLINE_EXCEEDED, + handles.first.wait(WaitFlags.none().setReadable(true), 0)); + + // Testing read on an empty pipe. + boolean exception = false; + try { + handles.first.readMessage(null, 0, MessagePipeHandle.ReadFlags.none()); + } catch (MojoException e) { + assertEquals(MojoResult.SHOULD_WAIT, e.getMojoResult()); + exception = true; + } + assertTrue(exception); + + // Closing a pipe while waiting. + WORKER.schedule(new CloseHandle(handles.first), 10, TimeUnit.MILLISECONDS); + assertEquals(MojoResult.CANCELLED, + handles.first.wait(WaitFlags.none().setReadable(true), 1000000L)); + } finally { + handles.first.close(); + handles.second.close(); + } + + handles = core.createMessagePipe(); + + try { + // Closing the other pipe while waiting. + WORKER.schedule(new CloseHandle(handles.first), 10, TimeUnit.MILLISECONDS); + assertEquals(MojoResult.FAILED_PRECONDITION, + handles.second.wait(WaitFlags.none().setReadable(true), 1000000L)); + + // Waiting on a closed pipe. + assertEquals(MojoResult.FAILED_PRECONDITION, + handles.second.wait(WaitFlags.none().setReadable(true), 0)); + assertEquals(MojoResult.FAILED_PRECONDITION, + handles.second.wait(WaitFlags.none().setWritable(true), 0)); + } finally { + handles.first.close(); + handles.second.close(); + } + + } + + /** + * Testing {@link MessagePipeHandle}. + */ + @SmallTest + public void testMessagePipeSend() { + Core core = CoreSingleton.getInstance(); + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + + try { + checkSendingMessage(handles.first, handles.second); + checkSendingMessage(handles.second, handles.first); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing {@link MessagePipeHandle}. + */ + @SmallTest + public void testMessagePipeReceiveOnSmallBuffer() { + Random random = new Random(); + Core core = CoreSingleton.getInstance(); + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + + try { + // Writing a random 8 bytes message. + byte[] bytes = new byte[8]; + random.nextBytes(bytes); + ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length); + buffer.put(bytes); + handles.first.writeMessage(buffer, null, MessagePipeHandle.WriteFlags.none()); + + ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(1); + MessagePipeHandle.ReadMessageResult result = handles.second.readMessage(receiveBuffer, + 0, + MessagePipeHandle.ReadFlags.none()); + assertFalse(result.getWasMessageRead()); + assertEquals(bytes.length, result.getMessageSize()); + assertEquals(0, result.getHandlesCount()); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing {@link MessagePipeHandle}. + */ + @SmallTest + public void testMessagePipeSendHandles() { + Core core = CoreSingleton.getInstance(); + Pair<MessagePipeHandle, MessagePipeHandle> handles = core.createMessagePipe(); + Pair<MessagePipeHandle, MessagePipeHandle> handlesToShare = core.createMessagePipe(); + + try { + handles.first.writeMessage(null, + Collections.<Handle> singletonList(handlesToShare.second), + WriteFlags.none()); + assertFalse(handlesToShare.second.isValid()); + ReadMessageResult readMessageResult = handles.second.readMessage(null, 1, + ReadFlags.none()); + assertEquals(1, readMessageResult.getHandlesCount()); + MessagePipeHandle newHandle = readMessageResult.getHandles().get(0) + .toMessagePipeHandle(); + try { + assertTrue(newHandle.isValid()); + checkSendingMessage(handlesToShare.first, newHandle); + checkSendingMessage(newHandle, handlesToShare.first); + } finally { + newHandle.close(); + } + } finally { + handles.first.close(); + handles.second.close(); + handlesToShare.first.close(); + handlesToShare.second.close(); + } + } + + private static void createAndCloseDataPipe(DataPipe.CreateOptions options) { + Core core = CoreSingleton.getInstance(); + Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe( + options); + handles.first.close(); + handles.second.close(); + } + + /** + * Testing {@link DataPipe}. + */ + @SmallTest + public void testDataPipeCreation() { + // Create datapipe with null options. + createAndCloseDataPipe(null); + DataPipe.CreateOptions options = new DataPipe.CreateOptions(); + // Create datapipe with element size set. + options.setElementNumBytes(24); + createAndCloseDataPipe(options); + // Create datapipe with a flag set. + options.getFlags().setMayDiscard(true); + createAndCloseDataPipe(options); + // Create datapipe with capacity set. + options.setCapacityNumBytes(1024 * options.getElementNumBytes()); + createAndCloseDataPipe(options); + } + + /** + * Testing {@link DataPipe}. + */ + @SmallTest + public void testDataPipeSend() { + Core core = CoreSingleton.getInstance(); + Random random = new Random(); + + Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null); + try { + // Writing a random 8 bytes message. + byte[] bytes = new byte[8]; + random.nextBytes(bytes); + ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length); + buffer.put(bytes); + int result = handles.first.writeData(buffer, DataPipe.WriteFlags.none()); + assertEquals(bytes.length, result); + + // Query number of bytes available. + result = handles.second.readData(null, + DataPipe.ReadFlags.none().query(true)); + assertEquals(bytes.length, result); + + // Read into a buffer. + ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length); + result = handles.second.readData(receiveBuffer, + DataPipe.ReadFlags.none()); + assertEquals(bytes.length, result); + assertEquals(0, receiveBuffer.position()); + assertEquals(bytes.length, receiveBuffer.limit()); + byte[] receivedBytes = new byte[bytes.length]; + receiveBuffer.get(receivedBytes); + assertTrue(Arrays.equals(bytes, receivedBytes)); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing {@link DataPipe}. + */ + @SmallTest + public void testDataPipeTwoPhaseSend() { + Random random = new Random(); + Core core = CoreSingleton.getInstance(); + Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null); + + try { + // Writing a random 8 bytes message. + byte[] bytes = new byte[8]; + random.nextBytes(bytes); + ByteBuffer buffer = handles.first.beginWriteData(bytes.length, + DataPipe.WriteFlags.none()); + assertTrue(buffer.capacity() >= bytes.length); + buffer.put(bytes); + handles.first.endWriteData(bytes.length); + + // Read into a buffer. + ByteBuffer receiveBuffer = handles.second.beginReadData(bytes.length, + DataPipe.ReadFlags.none()); + assertEquals(0, receiveBuffer.position()); + assertEquals(bytes.length, receiveBuffer.limit()); + byte[] receivedBytes = new byte[bytes.length]; + receiveBuffer.get(receivedBytes); + assertTrue(Arrays.equals(bytes, receivedBytes)); + handles.second.endReadData(bytes.length); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing {@link DataPipe}. + */ + @SmallTest + public void testDataPipeDiscard() { + Random random = new Random(); + Core core = CoreSingleton.getInstance(); + Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles = core.createDataPipe(null); + + try { + // Writing a random 8 bytes message. + byte[] bytes = new byte[8]; + random.nextBytes(bytes); + ByteBuffer buffer = ByteBuffer.allocateDirect(bytes.length); + buffer.put(bytes); + int result = handles.first.writeData(buffer, DataPipe.WriteFlags.none()); + assertEquals(bytes.length, result); + + // Discard bytes. + final int nbBytesToDiscard = 4; + assertEquals(nbBytesToDiscard, + handles.second.discardData(nbBytesToDiscard, DataPipe.ReadFlags.none())); + + // Read into a buffer. + ByteBuffer receiveBuffer = ByteBuffer.allocateDirect(bytes.length - nbBytesToDiscard); + result = handles.second.readData(receiveBuffer, + DataPipe.ReadFlags.none()); + assertEquals(bytes.length - nbBytesToDiscard, result); + assertEquals(0, receiveBuffer.position()); + assertEquals(bytes.length - nbBytesToDiscard, receiveBuffer.limit()); + byte[] receivedBytes = new byte[bytes.length - nbBytesToDiscard]; + receiveBuffer.get(receivedBytes); + assertTrue(Arrays.equals(Arrays.copyOfRange(bytes, nbBytesToDiscard, bytes.length), + receivedBytes)); + } finally { + handles.first.close(); + handles.second.close(); + } + } + + /** + * Testing {@link SharedBufferHandle}. + */ + @SmallTest + public void testSharedBufferCreation() { + Core core = CoreSingleton.getInstance(); + // Test creation with empty options. + core.createSharedBuffer(null, 8).close(); + // Test creation with default options. + core.createSharedBuffer(new SharedBufferHandle.CreateOptions(), 8); + } + + /** + * Testing {@link SharedBufferHandle}. + */ + @SmallTest + public void testSharedBufferDuplication() { + Core core = CoreSingleton.getInstance(); + SharedBufferHandle handle = core.createSharedBuffer(null, 8); + try { + // Test duplication with empty options. + handle.duplicate(null).close(); + // Test creation with default options. + handle.duplicate(new SharedBufferHandle.DuplicateOptions()).close(); + } finally { + handle.close(); + } + } + + /** + * Testing {@link SharedBufferHandle}. + */ + @SmallTest + public void testSharedBufferSending() { + Random random = new Random(); + Core core = CoreSingleton.getInstance(); + SharedBufferHandle handle = core.createSharedBuffer(null, 8); + SharedBufferHandle newHandle = handle.duplicate(null); + + try { + ByteBuffer buffer1 = handle.map(0, 8, MapFlags.none()); + assertEquals(8, buffer1.capacity()); + ByteBuffer buffer2 = newHandle.map(0, 8, MapFlags.none()); + assertEquals(8, buffer2.capacity()); + + byte[] bytes = new byte[8]; + random.nextBytes(bytes); + buffer1.put(bytes); + + byte[] receivedBytes = new byte[bytes.length]; + buffer2.get(receivedBytes); + + assertTrue(Arrays.equals(bytes, receivedBytes)); + + handle.unmap(buffer1); + newHandle.unmap(buffer2); + } finally { + handle.close(); + newHandle.close(); + } + } + + private native void nativeInitApplicationContext(Context context); +} diff --git a/mojo/android/system/core_impl.cc b/mojo/android/system/core_impl.cc new file mode 100644 index 0000000..d7552c1 --- /dev/null +++ b/mojo/android/system/core_impl.cc @@ -0,0 +1,293 @@ +// 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. + +#include "mojo/android/system/core_impl.h" + +#include "base/android/base_jni_registrar.h" +#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 "jni/CoreImpl_jni.h" +#include "mojo/embedder/embedder.h" +#include "mojo/public/c/system/core.h" + +namespace mojo { +namespace android { + +static void Constructor(JNIEnv* env, jobject jcaller) { + mojo::embedder::Init(); +} + +static jlong GetTimeTicksNow(JNIEnv* env, jobject jcaller) { + return MojoGetTimeTicksNow(); +} + +static jint WaitMany(JNIEnv* env, + jobject jcaller, + jobject buffer, + jlong deadline) { + // Buffer contains first the list of handles, then the list of flags. + const void* buffer_start = env->GetDirectBufferAddress(buffer); + DCHECK(buffer_start); + const size_t record_size = 8; + const size_t buffer_size = env->GetDirectBufferCapacity(buffer); + DCHECK_EQ(buffer_size % record_size, 0u); + + const size_t nb_handles = buffer_size / record_size; + const MojoHandle* handle_start = static_cast<const MojoHandle*>(buffer_start); + const MojoWaitFlags* flags_start = + static_cast<const MojoWaitFlags*>(handle_start + nb_handles); + return MojoWaitMany(handle_start, flags_start, nb_handles, deadline); +} + +static jobject CreateMessagePipe(JNIEnv* env, jobject jcaller) { + MojoHandle handle1; + MojoHandle handle2; + MojoResult result = MojoCreateMessagePipe(&handle1, &handle2); + return Java_CoreImpl_newNativeCreationResult(env, result, handle1, handle2) + .Release(); +} + +static jobject CreateDataPipe(JNIEnv* env, + jobject jcaller, + jobject options_buffer) { + const MojoCreateDataPipeOptions* options = NULL; + if (options_buffer) { + const void* buffer_start = env->GetDirectBufferAddress(options_buffer); + DCHECK(buffer_start); + const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer); + DCHECK_EQ(buffer_size, sizeof(MojoCreateDataPipeOptions)); + options = static_cast<const MojoCreateDataPipeOptions*>(buffer_start); + DCHECK_EQ(options->struct_size, buffer_size); + } + MojoHandle handle1; + MojoHandle handle2; + MojoResult result = MojoCreateDataPipe(options, &handle1, &handle2); + return Java_CoreImpl_newNativeCreationResult(env, result, handle1, handle2) + .Release(); +} + +static jobject CreateSharedBuffer(JNIEnv* env, + jobject jcaller, + jobject options_buffer, + jlong num_bytes) { + const MojoCreateSharedBufferOptions* options = 0; + if (options_buffer) { + const void* buffer_start = env->GetDirectBufferAddress(options_buffer); + DCHECK(buffer_start); + const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer); + DCHECK_EQ(buffer_size, sizeof(MojoCreateSharedBufferOptions)); + options = static_cast<const MojoCreateSharedBufferOptions*>(buffer_start); + DCHECK_EQ(options->struct_size, buffer_size); + } + MojoHandle handle; + MojoResult result = MojoCreateSharedBuffer(options, num_bytes, &handle); + return Java_CoreImpl_newNativeCreationResult(env, result, handle, 0) + .Release(); +} + +static jint Close(JNIEnv* env, jobject jcaller, jint mojo_handle) { + return MojoClose(mojo_handle); +} + +static jint Wait(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jint flags, + jlong deadline) { + return MojoWait(mojo_handle, flags, deadline); +} + +static jint WriteMessage(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jobject bytes, + jint num_bytes, + jobject handles_buffer, + jint flags) { + const void* buffer_start = 0; + uint32_t buffer_size = 0; + if (bytes) { + buffer_start = env->GetDirectBufferAddress(bytes); + DCHECK(buffer_start); + DCHECK(env->GetDirectBufferCapacity(bytes) >= num_bytes); + buffer_size = num_bytes; + } + const MojoHandle* handles = 0; + uint32_t num_handles = 0; + if (handles_buffer) { + handles = + static_cast<MojoHandle*>(env->GetDirectBufferAddress(handles_buffer)); + num_handles = env->GetDirectBufferCapacity(handles_buffer) / 4; + } + // Java code will handle invalidating handles if the write succeeded. + return MojoWriteMessage( + mojo_handle, buffer_start, buffer_size, handles, num_handles, flags); +} + +static jobject ReadMessage(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jobject bytes, + jobject handles_buffer, + jint flags) { + void* buffer_start = 0; + uint32_t buffer_size = 0; + if (bytes) { + buffer_start = env->GetDirectBufferAddress(bytes); + DCHECK(buffer_start); + buffer_size = env->GetDirectBufferCapacity(bytes); + } + MojoHandle* handles = 0; + uint32_t num_handles = 0; + if (handles_buffer) { + handles = + static_cast<MojoHandle*>(env->GetDirectBufferAddress(handles_buffer)); + num_handles = env->GetDirectBufferCapacity(handles_buffer) / 4; + } + MojoResult result = MojoReadMessage( + mojo_handle, buffer_start, &buffer_size, handles, &num_handles, flags); + // Jave code will handle taking ownership of any received handle. + return Java_CoreImpl_newNativeReadMessageResult( + env, result, buffer_size, num_handles).Release(); +} + +static jint ReadData(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jobject elements, + jint elements_capacity, + jint flags) { + void* buffer_start = 0; + uint32_t buffer_size = elements_capacity; + if (elements) { + buffer_start = env->GetDirectBufferAddress(elements); + DCHECK(buffer_start); + DCHECK(elements_capacity <= env->GetDirectBufferCapacity(elements)); + } + MojoResult result = + MojoReadData(mojo_handle, buffer_start, &buffer_size, flags); + if (result < 0) { + return result; + } + return buffer_size; +} + +static jobject BeginReadData(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jint num_bytes, + jint flags) { + void const* buffer = 0; + uint32_t buffer_size = num_bytes; + MojoResult result = + MojoBeginReadData(mojo_handle, &buffer, &buffer_size, flags); + jobject byte_buffer = 0; + if (result == MOJO_RESULT_OK) { + byte_buffer = + env->NewDirectByteBuffer(const_cast<void*>(buffer), buffer_size); + } + return Java_CoreImpl_newNativeCodeAndBufferResult(env, result, byte_buffer) + .Release(); +} + +static jint EndReadData(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jint num_bytes_read) { + return MojoEndReadData(mojo_handle, num_bytes_read); +} + +static jint WriteData(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jobject elements, + jint limit, + jint flags) { + void* buffer_start = env->GetDirectBufferAddress(elements); + DCHECK(buffer_start); + DCHECK(limit <= env->GetDirectBufferCapacity(elements)); + uint32_t buffer_size = limit; + MojoResult result = + MojoWriteData(mojo_handle, buffer_start, &buffer_size, flags); + if (result < 0) { + return result; + } + return buffer_size; +} + +static jobject BeginWriteData(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jint num_bytes, + jint flags) { + void* buffer = 0; + uint32_t buffer_size = num_bytes; + MojoResult result = + MojoBeginWriteData(mojo_handle, &buffer, &buffer_size, flags); + jobject byte_buffer = 0; + if (result == MOJO_RESULT_OK) { + byte_buffer = env->NewDirectByteBuffer(buffer, buffer_size); + } + return Java_CoreImpl_newNativeCodeAndBufferResult(env, result, byte_buffer) + .Release(); +} + +static jint EndWriteData(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jint num_bytes_written) { + return MojoEndWriteData(mojo_handle, num_bytes_written); +} + +static jobject Duplicate(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jobject options_buffer) { + const MojoDuplicateBufferHandleOptions* options = 0; + if (options_buffer) { + const void* buffer_start = env->GetDirectBufferAddress(options_buffer); + DCHECK(buffer_start); + const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer); + DCHECK_EQ(buffer_size, sizeof(MojoDuplicateBufferHandleOptions)); + options = + static_cast<const MojoDuplicateBufferHandleOptions*>(buffer_start); + DCHECK_EQ(options->struct_size, buffer_size); + } + MojoHandle handle; + MojoResult result = MojoDuplicateBufferHandle(mojo_handle, options, &handle); + return Java_CoreImpl_newNativeCreationResult(env, result, handle, 0) + .Release(); +} + +static jobject Map(JNIEnv* env, + jobject jcaller, + jint mojo_handle, + jlong offset, + jlong num_bytes, + jint flags) { + void* buffer = 0; + MojoResult result = + MojoMapBuffer(mojo_handle, offset, num_bytes, &buffer, flags); + jobject byte_buffer = 0; + if (result == MOJO_RESULT_OK) { + byte_buffer = env->NewDirectByteBuffer(buffer, num_bytes); + } + return Java_CoreImpl_newNativeCodeAndBufferResult(env, result, byte_buffer) + .Release(); +} + +static int Unmap(JNIEnv* env, jobject jcaller, jobject buffer) { + void* buffer_start = env->GetDirectBufferAddress(buffer); + DCHECK(buffer_start); + return MojoUnmapBuffer(buffer_start); +} + +bool RegisterCoreImpl(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android +} // namespace mojo diff --git a/mojo/android/system/core_impl.h b/mojo/android/system/core_impl.h new file mode 100644 index 0000000..c624999 --- /dev/null +++ b/mojo/android/system/core_impl.h @@ -0,0 +1,20 @@ +// 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. + +#ifndef MOJO_ANDROID_SYSTEM_CORE_IMPL_H_ +#define MOJO_ANDROID_SYSTEM_CORE_IMPL_H_ + +#include <jni.h> + +#include "base/android/jni_android.h" + +namespace mojo { +namespace android { + +JNI_EXPORT bool RegisterCoreImpl(JNIEnv* env); + +} // namespace android +} // namespace mojo + +#endif // MOJO_ANDROID_SYSTEM_CORE_IMPL_H_ diff --git a/mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java b/mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java new file mode 100644 index 0000000..1d8e56b --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java @@ -0,0 +1,584 @@ +// 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.base.CalledByNative; +import org.chromium.base.JNINamespace; +import org.chromium.mojo.system.DataPipe.ConsumerHandle; +import org.chromium.mojo.system.DataPipe.ProducerHandle; +import org.chromium.mojo.system.SharedBufferHandle.DuplicateOptions; +import org.chromium.mojo.system.SharedBufferHandle.MapFlags; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +/** + * Implementation of {@link Core}. + */ +@JNINamespace("mojo::android") +class CoreImpl implements Core { + + /** + * Discard flag for the |MojoReadData| operation. + */ + private static final int MOJO_READ_DATA_FLAG_DISCARD = 1 << 1; + + /** + * the size of a handle, in bytes. + */ + private static final int HANDLE_SIZE = 4; + + /** + * the size of a flag, in bytes. + */ + private static final int FLAG_SIZE = 4; + + /** + * The singleton instance. + */ + private static Core sINSTANCE = null; + + /** + * @return the instance. + */ + static synchronized Core getInstance() { + if (sINSTANCE == null) { + sINSTANCE = new CoreImpl(); + } + return sINSTANCE; + } + + private CoreImpl() { + nativeConstructor(); + } + + /** + * @see Core#getTimeTicksNow() + */ + @Override + public long getTimeTicksNow() { + return nativeGetTimeTicksNow(); + } + + /** + * @see Core#waitMany(List, long) + */ + @Override + public WaitManyResult waitMany(List<Pair<Handle, WaitFlags>> handles, long deadline) { + // Allocate a direct buffer to allow native code not to reach back to java. Buffer will + // contain all mojo handles, followed by all flags values. + ByteBuffer buffer = allocateDirectBuffer(handles.size() * 8); + int index = 0; + for (Pair<Handle, WaitFlags> handle : handles) { + HandleImpl realHandler = (HandleImpl) handle.first; + buffer.putInt(HANDLE_SIZE * index, realHandler.getMojoHandle()); + buffer.putInt(HANDLE_SIZE * handles.size() + FLAG_SIZE * index, + handle.second.getFlags()); + index++; + } + int code = nativeWaitMany(buffer, deadline); + WaitManyResult result = new WaitManyResult(); + // If result is greater than 0, result is the indexed of the available handle. To make sure + // it cannot be misinterpreted, set handleIndex to a negative number in case of error. + result.setHandleIndex(code); + result.setMojoResult(filterMojoResultForWait(code)); + return result; + } + + /** + * @see Core#wait(Handle, WaitFlags, long) + */ + @Override + public int wait(Handle handle, WaitFlags flags, long deadline) { + return filterMojoResultForWait(nativeWait(((HandleImpl) handle).getMojoHandle(), + flags.getFlags(), deadline)); + } + + /** + * @see Core#createMessagePipe() + */ + @Override + public Pair<MessagePipeHandle, MessagePipeHandle> createMessagePipe() { + NativeCreationResult result = nativeCreateMessagePipe(); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return Pair.create( + new MessagePipeHandleImpl(this, result.getMojoHandle1()), + new MessagePipeHandleImpl(this, result.getMojoHandle2())); + } + + /** + * @see Core#createDataPipe(DataPipe.CreateOptions) + */ + @Override + public Pair<ProducerHandle, ConsumerHandle> createDataPipe(DataPipe.CreateOptions options) { + ByteBuffer optionsBuffer = null; + if (options != null) { + optionsBuffer = allocateDirectBuffer(16); + optionsBuffer.putInt(0, 16); + optionsBuffer.putInt(4, options.getFlags().getFlags()); + optionsBuffer.putInt(8, options.getElementNumBytes()); + optionsBuffer.putInt(12, options.getCapacityNumBytes()); + } + NativeCreationResult result = nativeCreateDataPipe(optionsBuffer); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return Pair.create( + new DataPipeProducerHandleImpl(this, result.getMojoHandle1()), + new DataPipeConsumerHandleImpl(this, result.getMojoHandle2())); + } + + /** + * @see Core#createSharedBuffer(SharedBufferHandle.CreateOptions, long) + */ + @Override + public SharedBufferHandle createSharedBuffer( + SharedBufferHandle.CreateOptions options, long numBytes) { + ByteBuffer optionsBuffer = null; + if (options != null) { + optionsBuffer = allocateDirectBuffer(8); + optionsBuffer.putInt(0, 8); + optionsBuffer.putInt(4, options.getFlags().getFlags()); + } + NativeCreationResult result = nativeCreateSharedBuffer(optionsBuffer, numBytes); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + assert result.getMojoHandle2() == 0; + return new SharedBufferHandleImpl(this, result.getMojoHandle1()); + } + + int closeWithResult(int mojoHandle) { + return nativeClose(mojoHandle); + } + + void close(int mojoHandle) { + int mojoResult = nativeClose(mojoHandle); + if (mojoResult != MojoResult.OK) { + throw new MojoException(mojoResult); + } + } + + /** + * @see MessagePipeHandle#writeMessage(ByteBuffer, List, MessagePipeHandle.WriteFlags) + */ + void writeMessage(MessagePipeHandleImpl pipeHandle, ByteBuffer bytes, + List<Handle> handles, MessagePipeHandle.WriteFlags flags) { + ByteBuffer handlesBuffer = null; + if (handles != null && !handles.isEmpty()) { + handlesBuffer = allocateDirectBuffer(handles.size() * HANDLE_SIZE); + for (Handle handle : handles) { + HandleImpl realHandle = (HandleImpl) handle; + handlesBuffer.putInt(realHandle.getMojoHandle()); + } + handlesBuffer.position(0); + } + int mojoResult = nativeWriteMessage(pipeHandle.getMojoHandle(), bytes, + bytes == null ? 0 : bytes.limit(), handlesBuffer, + flags.getFlags()); + if (mojoResult != MojoResult.OK) { + throw new MojoException(mojoResult); + } + // Success means the handles have been invalidated. + if (handles != null) { + for (Handle handle : handles) { + ((HandleImpl) handle).invalidateHandle(); + } + } + } + + /** + * @see MessagePipeHandle#readMessage(ByteBuffer, int, MessagePipeHandle.ReadFlags) + */ + MessagePipeHandle.ReadMessageResult readMessage(MessagePipeHandleImpl handle, + ByteBuffer bytes, int maxNumberOfHandles, + MessagePipeHandle.ReadFlags flags) { + ByteBuffer handlesBuffer = null; + if (maxNumberOfHandles > 0) { + handlesBuffer = allocateDirectBuffer(maxNumberOfHandles * HANDLE_SIZE); + } + NativeReadMessageResult result = nativeReadMessage( + handle.getMojoHandle(), bytes, handlesBuffer, flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK && + result.getMojoResult() != MojoResult.RESOURCE_EXHAUSTED) { + throw new MojoException(result.getMojoResult()); + } + + if (result.getMojoResult() == MojoResult.OK) { + if (bytes != null) { + bytes.position(0); + bytes.limit(result.getReadMessageResult().getMessageSize()); + } + + List<UntypedHandle> handles = new ArrayList<UntypedHandle>( + result.getReadMessageResult().getHandlesCount()); + for (int i = 0; i < result.getReadMessageResult().getHandlesCount(); ++i) { + int mojoHandle = handlesBuffer.getInt(HANDLE_SIZE * i); + handles.add(new UntypedHandleImpl(this, mojoHandle)); + } + result.getReadMessageResult().setHandles(handles); + } + return result.getReadMessageResult(); + } + + /** + * @see DataPipe.ConsumerHandle#discardData(int, DataPipe.ReadFlags) + */ + int discardData(DataPipeConsumerHandleImpl handle, int numBytes, + DataPipe.ReadFlags flags) { + int result = nativeReadData(handle.getMojoHandle(), null, numBytes, + flags.getFlags() | MOJO_READ_DATA_FLAG_DISCARD); + if (result < 0) { + throw new MojoException(result); + } + return result; + } + + /** + * @see DataPipe.ConsumerHandle#readData(ByteBuffer, DataPipe.ReadFlags) + */ + int readData(DataPipeConsumerHandleImpl handle, ByteBuffer elements, + DataPipe.ReadFlags flags) { + int result = nativeReadData(handle.getMojoHandle(), elements, + elements == null ? 0 : elements.capacity(), + flags.getFlags()); + if (result < 0) { + throw new MojoException(result); + } + if (elements != null) { + elements.limit(result); + } + return result; + } + + /** + * @see DataPipe.ConsumerHandle#beginReadData(int, DataPipe.ReadFlags) + */ + ByteBuffer beginReadData(DataPipeConsumerHandleImpl handle, + int numBytes, DataPipe.ReadFlags flags) { + NativeCodeAndBufferResult result = nativeBeginReadData( + handle.getMojoHandle(), + numBytes, + flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return result.getBuffer().asReadOnlyBuffer(); + } + + /** + * @see DataPipe.ConsumerHandle#endReadData(int) + */ + void endReadData(DataPipeConsumerHandleImpl handle, + int numBytesRead) { + int result = nativeEndReadData(handle.getMojoHandle(), numBytesRead); + if (result != MojoResult.OK) { + throw new MojoException(result); + } + } + + /** + * @see DataPipe.ProducerHandle#writeData(ByteBuffer, DataPipe.WriteFlags) + */ + int writeData(DataPipeProducerHandleImpl handle, ByteBuffer elements, + DataPipe.WriteFlags flags) { + return nativeWriteData(handle.getMojoHandle(), elements, elements.limit(), + flags.getFlags()); + } + + /** + * @see DataPipe.ProducerHandle#beginWriteData(int, DataPipe.WriteFlags) + */ + ByteBuffer beginWriteData(DataPipeProducerHandleImpl handle, + int numBytes, DataPipe.WriteFlags flags) { + NativeCodeAndBufferResult result = nativeBeginWriteData( + handle.getMojoHandle(), + numBytes, + flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return result.getBuffer(); + } + + /** + * @see DataPipe.ProducerHandle#endWriteData(int) + */ + void endWriteData(DataPipeProducerHandleImpl handle, + int numBytesWritten) { + int result = nativeEndWriteData(handle.getMojoHandle(), numBytesWritten); + if (result != MojoResult.OK) { + throw new MojoException(result); + } + } + + /** + * @see SharedBufferHandle#duplicate(DuplicateOptions) + */ + SharedBufferHandle duplicate(SharedBufferHandleImpl handle, + DuplicateOptions options) { + ByteBuffer optionsBuffer = null; + if (options != null) { + optionsBuffer = allocateDirectBuffer(8); + optionsBuffer.putInt(0, 8); + optionsBuffer.putInt(4, options.getFlags().getFlags()); + } + NativeCreationResult result = nativeDuplicate(handle.getMojoHandle(), + optionsBuffer); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + assert result.getMojoHandle2() == 0; + return new SharedBufferHandleImpl(this, result.getMojoHandle1()); + } + + /** + * @see SharedBufferHandle#map(long, long, MapFlags) + */ + ByteBuffer map(SharedBufferHandleImpl handle, long offset, long numBytes, + MapFlags flags) { + NativeCodeAndBufferResult result = nativeMap(handle.getMojoHandle(), offset, numBytes, + flags.getFlags()); + if (result.getMojoResult() != MojoResult.OK) { + throw new MojoException(result.getMojoResult()); + } + return result.getBuffer(); + } + + /** + * @see SharedBufferHandle#unmap(ByteBuffer) + */ + void unmap(ByteBuffer buffer) { + int result = nativeUnmap(buffer); + if (result != MojoResult.OK) { + throw new MojoException(result); + } + } + + private static int filterMojoResultForWait(int code) { + if (code >= 0) { + return MojoResult.OK; + } + switch (code) { + case MojoResult.DEADLINE_EXCEEDED: + case MojoResult.CANCELLED: + case MojoResult.FAILED_PRECONDITION: + return code; + default: + throw new MojoException(code); + } + + } + + private static ByteBuffer allocateDirectBuffer(int capacity) { + ByteBuffer buffer = ByteBuffer.allocateDirect(capacity); + buffer.order(ByteOrder.nativeOrder()); + return buffer; + } + + private static class NativeCodeAndBufferResult { + private int mMojoResult; + private ByteBuffer mBuffer; + + /** + * @return the mojoResult + */ + public int getMojoResult() { + return mMojoResult; + } + + /** + * @param mojoResult the mojoResult to set + */ + public void setMojoResult(int mojoResult) { + mMojoResult = mojoResult; + } + + /** + * @return the buffer + */ + public ByteBuffer getBuffer() { + return mBuffer; + } + + /** + * @param buffer the buffer to set + */ + public void setBuffer(ByteBuffer buffer) { + mBuffer = buffer; + } + + } + + @CalledByNative + private static NativeCodeAndBufferResult newNativeCodeAndBufferResult(int mojoResult, + ByteBuffer buffer) { + NativeCodeAndBufferResult result = new NativeCodeAndBufferResult(); + result.setMojoResult(mojoResult); + result.setBuffer(buffer); + return result; + } + + private static class NativeReadMessageResult { + public int mMojoResult; + public MessagePipeHandle.ReadMessageResult mReadMessageResult; + + /** + * @return the mojoResult + */ + public int getMojoResult() { + return mMojoResult; + } + + /** + * @param mojoResult the mojoResult to set + */ + public void setMojoResult(int mojoResult) { + this.mMojoResult = mojoResult; + } + + /** + * @return the readMessageResult + */ + public MessagePipeHandle.ReadMessageResult getReadMessageResult() { + return mReadMessageResult; + } + + /** + * @param readMessageResult the readMessageResult to set + */ + public void setReadMessageResult(MessagePipeHandle.ReadMessageResult readMessageResult) { + this.mReadMessageResult = readMessageResult; + } + } + + @CalledByNative + private static NativeReadMessageResult newNativeReadMessageResult(int mojoResult, + int messageSize, + int handlesCount) { + NativeReadMessageResult result = new NativeReadMessageResult(); + if (mojoResult >= 0) { + result.setMojoResult(MojoResult.OK); + } else { + result.setMojoResult(mojoResult); + } + MessagePipeHandle.ReadMessageResult readMessageResult = + new MessagePipeHandle.ReadMessageResult(); + readMessageResult.setWasMessageRead(result.getMojoResult() == MojoResult.OK); + readMessageResult.setMessageSize(messageSize); + readMessageResult.setHandlesCount(handlesCount); + result.setReadMessageResult(readMessageResult); + return result; + } + + private static class NativeCreationResult { + private int mMojoResult; + private int mMojoHandle1; + private int mMojoHandle2; + + /** + * @return the mojoResult + */ + public int getMojoResult() { + return mMojoResult; + } + + /** + * @param mojoResult the mojoResult to set + */ + public void setMojoResult(int mojoResult) { + mMojoResult = mojoResult; + } + + /** + * @return the mojoHandle1 + */ + public int getMojoHandle1() { + return mMojoHandle1; + } + + /** + * @param mojoHandle1 the mojoHandle1 to set + */ + public void setMojoHandle1(int mojoHandle1) { + mMojoHandle1 = mojoHandle1; + } + + /** + * @return the mojoHandle2 + */ + public int getMojoHandle2() { + return mMojoHandle2; + } + + /** + * @param mojoHandle2 the mojoHandle2 to set + */ + public void setMojoHandle2(int mojoHandle2) { + mMojoHandle2 = mojoHandle2; + } + } + + @CalledByNative + private static NativeCreationResult newNativeCreationResult(int mojoResult, + int mojoHandle1, int mojoHandle2) { + NativeCreationResult result = new NativeCreationResult(); + result.setMojoResult(mojoResult); + result.setMojoHandle1(mojoHandle1); + result.setMojoHandle2(mojoHandle2); + return result; + } + + private native void nativeConstructor(); + + private native long nativeGetTimeTicksNow(); + + private native int nativeWaitMany(ByteBuffer buffer, long deadline); + + private native NativeCreationResult nativeCreateMessagePipe(); + + private native NativeCreationResult nativeCreateDataPipe(ByteBuffer optionsBuffer); + + private native NativeCreationResult nativeCreateSharedBuffer(ByteBuffer optionsBuffer, + long numBytes); + + private native int nativeClose(int mojoHandle); + + private native int nativeWait(int mojoHandle, int flags, long deadline); + + private native int nativeWriteMessage(int mojoHandle, ByteBuffer bytes, int numBytes, + ByteBuffer handlesBuffer, int flags); + + private native NativeReadMessageResult nativeReadMessage(int mojoHandle, ByteBuffer bytes, + ByteBuffer handlesBuffer, + int flags); + + private native int nativeReadData(int mojoHandle, ByteBuffer elements, int elementsSize, + int flags); + + private native NativeCodeAndBufferResult nativeBeginReadData(int mojoHandle, int numBytes, + int flags); + + private native int nativeEndReadData(int mojoHandle, int numBytesRead); + + private native int nativeWriteData(int mojoHandle, ByteBuffer elements, int limit, int flags); + + private native NativeCodeAndBufferResult nativeBeginWriteData(int mojoHandle, int numBytes, + int flags); + + private native int nativeEndWriteData(int mojoHandle, int numBytesWritten); + + private native NativeCreationResult nativeDuplicate(int mojoHandle, ByteBuffer optionsBuffer); + + private native NativeCodeAndBufferResult nativeMap(int mojoHandle, long offset, long numBytes, + int flags); + + private native int nativeUnmap(ByteBuffer buffer); + +} diff --git a/mojo/android/system/src/org/chromium/mojo/system/CoreSingleton.java b/mojo/android/system/src/org/chromium/mojo/system/CoreSingleton.java new file mode 100644 index 0000000..3cdbf96 --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/CoreSingleton.java @@ -0,0 +1,18 @@ +// 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; + +/** + * Access to the core singleton. + */ +public class CoreSingleton { + + /** + * Access to the {@link Core} singleton. + */ + public static Core getInstance() { + return CoreImpl.getInstance(); + } +} diff --git a/mojo/android/system/src/org/chromium/mojo/system/DataPipeConsumerHandleImpl.java b/mojo/android/system/src/org/chromium/mojo/system/DataPipeConsumerHandleImpl.java new file mode 100644 index 0000000..84985bf --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/DataPipeConsumerHandleImpl.java @@ -0,0 +1,63 @@ +// 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.DataPipe.ConsumerHandle; +import org.chromium.mojo.system.DataPipe.ReadFlags; + +import java.nio.ByteBuffer; + +/** + * Implementation of {@link ConsumerHandle}. + */ +class DataPipeConsumerHandleImpl extends HandleImpl implements ConsumerHandle { + + /** + * @see HandleImpl#HandleImpl(CoreImpl, int) + */ + DataPipeConsumerHandleImpl(CoreImpl core, int mojoHandle) { + super(core, mojoHandle); + } + + /** + * @see HandleImpl#HandleImpl(UntypedHandleImpl) + */ + DataPipeConsumerHandleImpl(UntypedHandleImpl other) { + super(other); + } + + /** + * @see ConsumerHandle#discardData(int, ReadFlags) + */ + @Override + public int discardData(int numBytes, ReadFlags flags) { + return mCore.discardData(this, numBytes, flags); + } + + /** + * @see ConsumerHandle#readData(ByteBuffer, ReadFlags) + */ + @Override + public int readData(ByteBuffer elements, ReadFlags flags) { + return mCore.readData(this, elements, flags); + } + + /** + * @see ConsumerHandle#beginReadData(int, ReadFlags) + */ + @Override + public ByteBuffer beginReadData(int numBytes, ReadFlags flags) { + return mCore.beginReadData(this, numBytes, flags); + } + + /** + * @see ConsumerHandle#endReadData(int) + */ + @Override + public void endReadData(int numBytesRead) { + mCore.endReadData(this, numBytesRead); + } + +} diff --git a/mojo/android/system/src/org/chromium/mojo/system/DataPipeProducerHandleImpl.java b/mojo/android/system/src/org/chromium/mojo/system/DataPipeProducerHandleImpl.java new file mode 100644 index 0000000..d6e00df --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/DataPipeProducerHandleImpl.java @@ -0,0 +1,55 @@ +// 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.DataPipe.ProducerHandle; +import org.chromium.mojo.system.DataPipe.WriteFlags; + +import java.nio.ByteBuffer; + +/** + * Implementation of {@link ProducerHandle}. + */ +class DataPipeProducerHandleImpl extends HandleImpl implements ProducerHandle { + + /** + * @see HandleImpl#HandleImpl(CoreImpl, int) + */ + DataPipeProducerHandleImpl(CoreImpl core, int mojoHandle) { + super(core, mojoHandle); + } + + /** + * @see HandleImpl#HandleImpl(UntypedHandleImpl) + */ + DataPipeProducerHandleImpl(UntypedHandleImpl handle) { + super(handle); + } + + /** + * @see DataPipe.ProducerHandle#writeData(ByteBuffer, WriteFlags) + */ + @Override + public int writeData(ByteBuffer elements, WriteFlags flags) { + return mCore.writeData(this, elements, flags); + } + + /** + * @see DataPipe.ProducerHandle#beginWriteData(int, WriteFlags) + */ + @Override + public ByteBuffer beginWriteData(int numBytes, WriteFlags flags) { + return mCore.beginWriteData(this, numBytes, flags); + } + + /** + * @see DataPipe.ProducerHandle#endWriteData(int) + */ + @Override + public void endWriteData(int numBytesWritten) { + mCore.endWriteData(this, numBytesWritten); + } + +} diff --git a/mojo/android/system/src/org/chromium/mojo/system/HandleImpl.java b/mojo/android/system/src/org/chromium/mojo/system/HandleImpl.java new file mode 100644 index 0000000..00cb9cd --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/HandleImpl.java @@ -0,0 +1,112 @@ +// 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 android.util.Log; + +import org.chromium.mojo.system.Core.WaitFlags; + +/** + * Implementation of {@link Handle}. + */ +class HandleImpl implements Handle { + + private static final String TAG = "HandleImpl"; + + private static final int INVALID_HANDLE = 0; + + /** + * The pointer to the scoped handle owned by this object. + */ + private int mMojoHandle; + + /** + * the core implementation. Will be used to delegate all behavior. + */ + protected CoreImpl mCore; + + /** + * Base constructor. Takes ownership of the passed handle. + */ + HandleImpl(CoreImpl core, int mojoHandle) { + mCore = core; + mMojoHandle = mojoHandle; + } + + /** + * Constructor for transforming an {@link UntypedHandle} into a specific one. + */ + HandleImpl(UntypedHandleImpl other) { + mCore = other.mCore; + HandleImpl otherAsHandleImpl = other; + int mojoHandle = otherAsHandleImpl.mMojoHandle; + otherAsHandleImpl.mMojoHandle = INVALID_HANDLE; + mMojoHandle = mojoHandle; + } + + /** + * @see org.chromium.mojo.system.Handle#close() + */ + @Override + public void close() { + if (mMojoHandle != INVALID_HANDLE) { + // After a close, the handle is invalid whether the close succeed or not. + int handle = mMojoHandle; + mMojoHandle = INVALID_HANDLE; + mCore.close(handle); + } + } + + /** + * @see org.chromium.mojo.system.Handle#wait(WaitFlags, long) + */ + @Override + public int wait(WaitFlags flags, long deadline) { + return mCore.wait(this, flags, deadline); + } + + /** + * @see org.chromium.mojo.system.Handle#isValid() + */ + @Override + public boolean isValid() { + return mMojoHandle != INVALID_HANDLE; + } + + /** + * Getter for the native scoped handle. + * + * @return the native scoped handle. + */ + int getMojoHandle() { + return mMojoHandle; + } + + /** + * invalidate the handle. The caller must ensures that the handle does not leak. + */ + void invalidateHandle() { + mMojoHandle = INVALID_HANDLE; + } + + /** + * Close the handle if it is valid. Necessary because we cannot let handle leak, and we cannot + * ensure that every handle will be manually closed. + * + * @see java.lang.Object#finalize() + */ + @Override + protected final void finalize() throws Throwable { + if (isValid()) { + // This should not happen, as the user of this class should close the handle. Adding a + // warning. + Log.w(TAG, "Handle was not closed."); + // Ignore result at this point. + mCore.closeWithResult(mMojoHandle); + } + super.finalize(); + } + +} diff --git a/mojo/android/system/src/org/chromium/mojo/system/MessagePipeHandleImpl.java b/mojo/android/system/src/org/chromium/mojo/system/MessagePipeHandleImpl.java new file mode 100644 index 0000000..6441b1c --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/MessagePipeHandleImpl.java @@ -0,0 +1,47 @@ +// 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 java.nio.ByteBuffer; +import java.util.List; + +/** + * Implementation of {@link MessagePipeHandle}. + */ +class MessagePipeHandleImpl extends HandleImpl implements MessagePipeHandle { + + /** + * @see HandleImpl#HandleImpl(CoreImpl, int) + */ + MessagePipeHandleImpl(CoreImpl core, int mojoHandle) { + super(core, mojoHandle); + } + + /** + * @see HandleImpl#HandleImpl(UntypedHandleImpl) + */ + MessagePipeHandleImpl(UntypedHandleImpl handle) { + super(handle); + } + + /** + * @see MessagePipeHandle#writeMessage(ByteBuffer, List, WriteFlags) + */ + @Override + public void writeMessage(ByteBuffer bytes, List<Handle> handles, WriteFlags flags) { + mCore.writeMessage(this, bytes, handles, flags); + } + + /** + * @see MessagePipeHandle#readMessage(ByteBuffer, int, ReadFlags) + */ + @Override + public ReadMessageResult readMessage(ByteBuffer bytes, + int maxNumberOfHandles, + ReadFlags flags) { + return mCore.readMessage(this, bytes, maxNumberOfHandles, flags); + } + +} diff --git a/mojo/android/system/src/org/chromium/mojo/system/SharedBufferHandleImpl.java b/mojo/android/system/src/org/chromium/mojo/system/SharedBufferHandleImpl.java new file mode 100644 index 0000000..4679bd0 --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/SharedBufferHandleImpl.java @@ -0,0 +1,52 @@ +// 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 java.nio.ByteBuffer; + +/** + * Implementation of {@link SharedBufferHandle}. + */ +class SharedBufferHandleImpl extends HandleImpl implements SharedBufferHandle { + + /** + * @see HandleImpl#HandleImpl(CoreImpl, int) + */ + SharedBufferHandleImpl(CoreImpl core, int mojoHandle) { + super(core, mojoHandle); + } + + /** + * @see HandleImpl#HandleImpl(UntypedHandleImpl) + */ + SharedBufferHandleImpl(UntypedHandleImpl handle) { + super(handle); + } + + /** + * @see SharedBufferHandle#duplicate(DuplicateOptions) + */ + @Override + public SharedBufferHandle duplicate(DuplicateOptions options) { + return mCore.duplicate(this, options); + } + + /** + * @see SharedBufferHandle#map(long, long, MapFlags) + */ + @Override + public ByteBuffer map(long offset, long numBytes, MapFlags flags) { + return mCore.map(this, offset, numBytes, flags); + } + + /** + * @see SharedBufferHandle#unmap(ByteBuffer) + */ + @Override + public void unmap(ByteBuffer buffer) { + mCore.unmap(buffer); + } + +} diff --git a/mojo/android/system/src/org/chromium/mojo/system/UntypedHandleImpl.java b/mojo/android/system/src/org/chromium/mojo/system/UntypedHandleImpl.java new file mode 100644 index 0000000..85c7691 --- /dev/null +++ b/mojo/android/system/src/org/chromium/mojo/system/UntypedHandleImpl.java @@ -0,0 +1,54 @@ +// 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.DataPipe.ConsumerHandle; +import org.chromium.mojo.system.DataPipe.ProducerHandle; + +/** + * Implementation of {@link UntypedHandle}. + */ +class UntypedHandleImpl extends HandleImpl implements UntypedHandle { + + /** + * @see HandleImpl#HandleImpl(CoreImpl, int) + */ + UntypedHandleImpl(CoreImpl core, int mojoHandle) { + super(core, mojoHandle); + } + + /** + * @see org.chromium.mojo.system.UntypedHandle#toMessagePipeHandle() + */ + @Override + public MessagePipeHandle toMessagePipeHandle() { + return new MessagePipeHandleImpl(this); + } + + /** + * @see org.chromium.mojo.system.UntypedHandle#toDataPipeConsumerHandle() + */ + @Override + public ConsumerHandle toDataPipeConsumerHandle() { + return new DataPipeConsumerHandleImpl(this); + } + + /** + * @see org.chromium.mojo.system.UntypedHandle#toDataPipeProducerHandle() + */ + @Override + public ProducerHandle toDataPipeProducerHandle() { + return new DataPipeProducerHandleImpl(this); + } + + /** + * @see org.chromium.mojo.system.UntypedHandle#toSharedBufferHandle() + */ + @Override + public SharedBufferHandle toSharedBufferHandle() { + return new SharedBufferHandleImpl(this); + } + +} diff --git a/mojo/mojo.gyp b/mojo/mojo.gyp index 198927f..24bedee 100644 --- a/mojo/mojo.gyp +++ b/mojo/mojo.gyp @@ -63,6 +63,14 @@ 'mojo_view_manager', ], }], + ['OS == "android"', { + 'dependencies': [ + 'mojo_public_java', + 'mojo_system_java', + 'libmojo_system_java', + 'mojo_test_apk', + ], + }], ] }, { @@ -565,41 +573,102 @@ ['OS=="android"', { 'targets': [ { - 'target_name': 'mojo_native_viewport_java', + 'target_name': 'mojo_jni_headers', + 'type': 'none', + 'dependencies': [ + 'mojo_java_set_jni_headers', + ], + 'sources': [ + 'android/javatests/src/org/chromium/mojo/system/CoreTest.java', + 'android/system/src/org/chromium/mojo/system/CoreImpl.java', + 'services/native_viewport/android/src/org/chromium/mojo/NativeViewportAndroid.java', + 'shell/android/apk/src/org/chromium/mojo_shell_apk/MojoMain.java', + ], + 'variables': { + 'jni_gen_package': 'mojo', + 'jni_generator_ptr_type': 'long', + }, + 'includes': [ '../build/jni_generator.gypi' ], + }, + { + 'target_name': 'mojo_system_java', 'type': 'none', 'dependencies': [ '../base/base.gyp:base_java', + 'mojo_public_java', ], 'variables': { - 'java_in_dir': '<(DEPTH)/mojo/services/native_viewport/android', + 'java_in_dir': '<(DEPTH)/mojo/android/system', }, 'includes': [ '../build/java.gypi' ], }, { - 'target_name': 'mojo_java_set_jni_headers', + 'target_name': 'libmojo_system_java', + 'type': 'static_library', + 'dependencies': [ + '../base/base.gyp:base', + '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + 'mojo_common_lib', + 'mojo_environment_chromium', + 'mojo_jni_headers', + 'mojo_shell_bindings', + 'mojo_shell_lib', + ], + 'sources': [ + 'android/system/core_impl.cc', + 'android/system/core_impl.h', + ], + }, + { + 'target_name': 'libmojo_java_unittest', + 'type': 'shared_library', + 'dependencies': [ + '../base/base.gyp:base', + 'libmojo_system_java', + 'mojo_jni_headers', + ], + 'sources': [ + 'android/javatests/core_test.cc', + 'android/javatests/core_test.h', + 'android/javatests/init_library.cc', + ], + }, + { + 'target_name': 'mojo_test_apk', 'type': 'none', + 'dependencies': [ + 'mojo_system_java', + '../base/base.gyp:base_java_test_support', + ], 'variables': { - 'jni_gen_package': 'mojo', - 'jni_generator_ptr_type': 'long', - 'input_java_class': 'java/util/HashSet.class', + 'apk_name': 'MojoTest', + 'java_in_dir': '<(DEPTH)/mojo/android/javatests', + 'resource_dir': '<(DEPTH)/mojo/android/javatests/apk', + 'native_lib_target': 'libmojo_java_unittest', + 'is_test_apk': 1, }, - 'includes': [ '../build/jar_file_jni_generator.gypi' ], + 'includes': [ '../build/java_apk.gypi' ], }, { - 'target_name': 'mojo_jni_headers', + 'target_name': 'mojo_native_viewport_java', 'type': 'none', 'dependencies': [ - 'mojo_java_set_jni_headers', - ], - 'sources': [ - 'services/native_viewport/android/src/org/chromium/mojo/NativeViewportAndroid.java', - 'shell/android/apk/src/org/chromium/mojo_shell_apk/MojoMain.java', + '../base/base.gyp:base_java', ], 'variables': { + 'java_in_dir': '<(DEPTH)/mojo/services/native_viewport/android', + }, + 'includes': [ '../build/java.gypi' ], + }, + { + 'target_name': 'mojo_java_set_jni_headers', + 'type': 'none', + 'variables': { 'jni_gen_package': 'mojo', 'jni_generator_ptr_type': 'long', - }, - 'includes': [ '../build/jni_generator.gypi' ], + 'input_java_class': 'java/util/HashSet.class', + }, + 'includes': [ '../build/jar_file_jni_generator.gypi' ], }, { 'target_name': 'libmojo_shell', diff --git a/mojo/mojo_public.gypi b/mojo/mojo_public.gypi index b4b1942..7f9c2f7 100644 --- a/mojo/mojo_public.gypi +++ b/mojo/mojo_public.gypi @@ -360,4 +360,18 @@ ], }, ], + 'conditions': [ + ['OS == "android"', { + 'targets': [ + { + 'target_name': 'mojo_public_java', + 'type': 'none', + 'variables': { + 'java_in_dir': 'public/java', + }, + 'includes': [ '../build/java.gypi' ], + }, + ], + }], + ], } diff --git a/mojo/public/java/src/org/chromium/mojo/system/Core.java b/mojo/public/java/src/org/chromium/mojo/system/Core.java new file mode 100644 index 0000000..8d084b3 --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/Core.java @@ -0,0 +1,178 @@ +// 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 java.util.List; + +/** + * Core mojo interface giving access to the base operations. See |src/mojo/public/c/system/core.h| + * for the underlying api. + */ +public interface Core { + + /** + * Used to indicate an infinite deadline (timeout). + */ + public static final long DEADLINE_INFINITE = -1; + + /** + * Flags for the wait operations on handles. + */ + public static class WaitFlags extends Flags<WaitFlags> { + /** + * Constructor. + * + * @param flags the serialized flags. + */ + private WaitFlags(int flags) { + super(flags); + } + + private static final int FLAG_NONE = 0; + private static final int FLAG_READABLE = 1 << 0; + private static final int FLAG_WRITABLE = 1 << 1; + private static final int FLAG_ALL = ~0; + + /** + * Change the readable bit of this flag. + * + * @param readable the new value of the readable bit. + * @return this. + */ + public WaitFlags setReadable(boolean readable) { + return setFlag(FLAG_READABLE, readable); + } + + /** + * Change the writable bit of this flag. + * + * @param writable the new value of the writable bit. + * @return this. + */ + public WaitFlags setWritable(boolean writable) { + return setFlag(FLAG_WRITABLE, writable); + } + + /** + * @return a flag with no bit set. + */ + public static WaitFlags none() { + return new WaitFlags(FLAG_NONE); + } + + /** + * @return a flag with all bits set. + */ + public static WaitFlags all() { + return new WaitFlags(FLAG_ALL); + } + } + + /** + * @return a platform-dependent monotonically increasing tick count representing "right now." + */ + public long getTimeTicksNow(); + + /** + * Waits on the given |handle| until the state indicated by |flags| is satisfied or until + * |deadline| has passed. + * + * @return |MojoResult.OK| if some flag in |flags| was satisfied (or is already satisfied). + * <p> + * |MojoResult.DEADLINE_EXCEEDED| if the deadline has passed without any of the flags + * begin satisfied. + * <p> + * |MojoResult.CANCELLED| if |handle| is closed concurrently by another thread. + * <p> + * |MojoResult.FAILED_PRECONDITION| if it is or becomes impossible that any flag in + * |flags| will ever be satisfied (for example, if the other endpoint is close). + */ + public int wait(Handle handle, WaitFlags flags, long deadline); + + /** + * Result for the |waitMany| method. + */ + public static class WaitManyResult { + + /** + * See |wait| for the different possible values. + */ + private int mMojoResult; + /** + * If |mojoResult| is |MojoResult.OK|, |handleIndex| is the index of the handle for which + * some flag was satisfied (or is already satisfied). If |mojoResult| is + * |MojoResult.CANCELLED| or |MojoResult.FAILED_PRECONDITION|, |handleIndex| is the index of + * the handle for which the issue occurred. + */ + private int mHandleIndex; + + /** + * @return the mojoResult + */ + public int getMojoResult() { + return mMojoResult; + } + + /** + * @param mojoResult the mojoResult to set + */ + public void setMojoResult(int mojoResult) { + mMojoResult = mojoResult; + } + + /** + * @return the handleIndex + */ + public int getHandleIndex() { + return mHandleIndex; + } + + /** + * @param handleIndex the handleIndex to set + */ + public void setHandleIndex(int handleIndex) { + mHandleIndex = handleIndex; + } + } + + /** + * Waits on handle in |handles| for at least one of them to satisfy the associated |WaitFlags|, + * or until |deadline| has passed. + * + * @returns a |WaitManyResult|. + */ + public WaitManyResult waitMany(List<Pair<Handle, WaitFlags>> handles, long deadline); + + /** + * Creates a message pipe, which is a bidirectional communication channel for framed data (i.e., + * messages). Messages can contain plain data and/or Mojo handles. + * + * @return the set of handles for the two endpoints (ports) of the message pipe. + */ + public Pair<MessagePipeHandle, MessagePipeHandle> createMessagePipe(); + + /** + * Creates a data pipe, which is a unidirectional communication channel for unframed data, with + * the given options. Data is unframed, but must come as (multiples of) discrete elements, of + * the size given in |options|. See |DataPipe.CreateOptions| for a description of the different + * options available for data pipes. |options| may be set to null for a data pipe with the + * default options (which will have an element size of one byte and have some system-dependent + * capacity). + * + * @return the set of handles for the two endpoints of the data pipe. + */ + public Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> createDataPipe( + DataPipe.CreateOptions options); + + /** + * Creates a buffer that can be shared between applications (by duplicating the handle -- see + * |SharedBufferHandle.duplicate()| -- and passing it over a message pipe). To access the + * buffer, one must call |SharedBufferHandle.map|. + * + * @return the new |SharedBufferHandle|. + */ + public SharedBufferHandle createSharedBuffer(SharedBufferHandle.CreateOptions options, + long numBytes); +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/DataPipe.java b/mojo/public/java/src/org/chromium/mojo/system/DataPipe.java new file mode 100644 index 0000000..175f97b --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/DataPipe.java @@ -0,0 +1,308 @@ +// 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 java.nio.ByteBuffer; + +/** + * Interface for data pipes. A data pipe is a unidirectional communication channel for unframed + * data. Data is unframed, but must come as (multiples of) discrete elements, of the size given at + * creation time. + */ +public interface DataPipe { + + /** + * Flags for the data pipe creation operation. + */ + public static class CreateFlags extends Flags<CreateFlags> { + private static final int FLAG_NONE = 0; + private static final int FLAG_MAY_DISCARD = 1 << 0; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flags. + */ + protected CreateFlags(int flags) { + super(flags); + } + + /** + * Change the may-discard bit of this flag. This indicates that the data pipe may discard + * data for whatever reason; best-effort delivery. In particular, if the capacity is + * reached, old data may be discard to make room for new data. + * + * @param mayDiscard the new value of the may-discard bit. + * @return this. + */ + public CreateFlags setMayDiscard(boolean mayDiscard) { + return setFlag(FLAG_MAY_DISCARD, mayDiscard); + } + + /** + * @return flags with no bit set. + */ + public static CreateFlags none() { + return new CreateFlags(FLAG_NONE); + } + + } + + /** + * Used to specify creation parameters for a data pipe to |Core.createDataPipe()|. + */ + public static class CreateOptions { + + /** + * Used to specify different modes of operation, see |DataPipe.CreateFlags|. + */ + private CreateFlags mFlags = CreateFlags.none(); + /** + * The size of an element, in bytes. All transactions and buffers will consist of an + * integral number of elements. Must be nonzero. + */ + private int mElementNumBytes; + /** + * The capacity of the data pipe, in number of bytes; must be a multiple of + * |element_num_bytes|. The data pipe will always be able to queue AT LEAST this much data. + * Set to zero to opt for a system-dependent automatically-calculated capacity (which will + * always be at least one element). + */ + private int mCapacityNumBytes; + + /** + * @return the flags + */ + public CreateFlags getFlags() { + return mFlags; + } + + /** + * @return the elementNumBytes + */ + public int getElementNumBytes() { + return mElementNumBytes; + } + + /** + * @param elementNumBytes the elementNumBytes to set + */ + public void setElementNumBytes(int elementNumBytes) { + mElementNumBytes = elementNumBytes; + } + + /** + * @return the capacityNumBytes + */ + public int getCapacityNumBytes() { + return mCapacityNumBytes; + } + + /** + * @param capacityNumBytes the capacityNumBytes to set + */ + public void setCapacityNumBytes(int capacityNumBytes) { + mCapacityNumBytes = capacityNumBytes; + } + + } + + /** + * Flags for the write operations on MessagePipeHandle . + */ + public static class WriteFlags extends Flags<WriteFlags> { + private static final int FLAG_NONE = 0; + private static final int FLAG_ALL_OR_NONE = 1 << 0; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flags. + */ + private WriteFlags(int flags) { + super(flags); + } + + /** + * Change the all-or-none bit of those flags. If set, write either all the elements + * requested or none of them. + * + * @param allOrNone the new value of all-or-none bit. + * @return this. + */ + public WriteFlags setAllOrNone(boolean allOrNone) { + return setFlag(FLAG_ALL_OR_NONE, allOrNone); + } + + /** + * @return a flag with no bit set. + */ + public static WriteFlags none() { + return new WriteFlags(FLAG_NONE); + } + } + + /** + * Flags for the read operations on MessagePipeHandle. + */ + public static class ReadFlags extends Flags<ReadFlags> { + private static final int FLAG_NONE = 0; + private static final int FLAG_ALL_OR_NONE = 1 << 0; + private static final int FLAG_QUERY = 1 << 2; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flag. + */ + private ReadFlags(int flags) { + super(flags); + } + + /** + * Change the all-or-none bit of this flag. If set, read (or discard) either the requested + * number of elements or none. + * + * @param allOrNone the new value of the all-or-none bit. + * @return this. + */ + public ReadFlags setAllOrNone(boolean allOrNone) { + return setFlag(FLAG_ALL_OR_NONE, allOrNone); + } + + /** + * Change the query bit of this flag. If set query the number of elements available to read. + * Mutually exclusive with |dicard| and |allOrNone| is ignored if this flag is set. + * + * @param query the new value of the query bit. + * @return this. + */ + public ReadFlags query(boolean query) { + return setFlag(FLAG_QUERY, query); + } + + /** + * @return a flag with no bit set. + */ + public static ReadFlags none() { + return new ReadFlags(FLAG_NONE); + } + + } + + /** + * Handle for the producer part of a data pipe. + */ + public static interface ProducerHandle extends Handle { + + /** + * Writes the given data to the data pipe producer. |elements| points to data; the buffer + * must be a direct ByteBuffer and the limit should be a multiple of the data pipe's element + * size. If |allOrNone| is set in |flags|, either all the data will be written or none is. + * <p> + * On success, returns the amount of data that was actually written. + * <p> + * Note: If the data pipe has the "may discard" option flag (specified on creation), this + * will discard as much data as required to write the given data, starting with the earliest + * written data that has not been consumed. However, even with "may discard", if the buffer + * limit is greater than the data pipe's capacity (and |allOrNone| is not set), this will + * write the maximum amount possible (namely, the data pipe's capacity) and return that + * amount. It will *not* discard data from |elements|. + * + * @return number of written bytes. + */ + public int writeData(ByteBuffer elements, WriteFlags flags); + + /** + * Begins a two-phase write to the data pipe producer . On success, returns a |ByteBuffer| + * to which the caller can write. If flags has |allOrNone| set, then the buffer capacity + * will be at least as large as |numBytes|, which must also be a multiple of the element + * size (if |allOrNone| is not set, |numBytes| is ignored and the caller must check the + * capacity of the buffer). + * <p> + * During a two-phase write, this handle is *not* writable. E.g., if another thread tries to + * write to it, it will throw a |MojoException| with code |MojoResult.BUSY|; that thread can + * then wait for this handle to become writable again. + * <p> + * Once the caller has finished writing data to the buffer, it should call |endWriteData()| + * to specify the amount written and to complete the two-phase write. + * <p> + * Note: If the data pipe has the "may discard" option flag (specified on creation) and + * |flags| has |allOrNone| set, this may discard some data. + * + * @return The buffer to write to. + */ + public ByteBuffer beginWriteData(int numBytes, WriteFlags flags); + + /** + * Ends a two-phase write to the data pipe producer that was begun by a call to + * |beginWriteData()| on the same handle. |numBytesWritten| should indicate the amount of + * data actually written; it must be less than or equal to the capacity of the buffer + * returned by |beginWriteData()| and must be a multiple of the element size. The buffer + * returned from |beginWriteData()| must have been filled with exactly |numBytesWritten| + * bytes of data. + * <p> + * On failure, the two-phase write (if any) is ended (so the handle may become writable + * again, if there's space available) but no data written to the buffer is "put into" the + * data pipe. + */ + public void endWriteData(int numBytesWritten); + } + + /** + * Handle for the consumer part of a data pipe. + */ + public static interface ConsumerHandle extends Handle { + + /** + * Discards data on the data pie consumer. This method discards up to |numBytes| (which + * again be a multiple of the element size) bytes of data, returning the amount actually + * discarded. if |flags| has |allOrNone|, it will either discard exactly |numBytes| bytes of + * data or none. In this case, |query| must not be set. + */ + public int discardData(int numBytes, ReadFlags flags); + + /** + * Reads data from the data pipe consumer. May also be used to query the amount of data + * available. If |flags| has not |query| set, this tries to read up to |elements| capacity + * (which must be a multiple of the data pipe's element size) bytes of data to |elements| + * and returns the amount actually read. |elements| must be a direct ByteBuffer. If flags + * has |allOrNone| set, it will either read exactly |elements| capacity bytes of data or + * none. + * <p> + * If flags has |query| set, it queries the amount of data available, returning the number + * of bytes available. In this case |allOrNone| is ignored, as are |elements|. + */ + public int readData(ByteBuffer elements, ReadFlags flags); + + /** + * Begins a two-phase read from the data pipe consumer. On success, returns a |ByteBuffer| + * from which the caller can read up to its limit bytes of data. If flags has |allOrNone| + * set, then the limit will be at least as large as |numBytes|, which must also be a + * multiple of the element size (if |allOrNone| is not set, |numBytes| is ignored). |flags| + * must not have |query| set. + * <p> + * During a two-phase read, this handle is *not* readable. E.g., if another thread tries to + * read from it, it will throw a |MojoException| with code |MojoResult.BUSY|; that thread + * can then wait for this handle to become readable again. + * <p> + * Once the caller has finished reading data from the buffer, it should call |endReadData()| + * to specify the amount read and to complete the two-phase read. + */ + public ByteBuffer beginReadData(int numBytes, ReadFlags flags); + + /** + * Ends a two-phase read from the data pipe consumer that was begun by a call to + * |beginReadData()| on the same handle. |numBytesRead| should indicate the amount of data + * actually read; it must be less than or equal to the limit of the buffer returned by + * |beginReadData()| and must be a multiple of the element size. + * <p> + * On failure, the two-phase read (if any) is ended (so the handle may become readable + * again) but no data is "removed" from the data pipe. + */ + public void endReadData(int numBytesRead); + } + +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/Flags.java b/mojo/public/java/src/org/chromium/mojo/system/Flags.java new file mode 100644 index 0000000..bfce6e4 --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/Flags.java @@ -0,0 +1,48 @@ +// 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; + +/** + * Base class for bit field used as flags. + * + * @param <F> the type of the flags. + */ +public abstract class Flags<F extends Flags<F>> { + private int mFlags; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flag. + */ + protected Flags(int flags) { + mFlags = flags; + } + + /** + * @return the computed flag. + */ + public int getFlags() { + return mFlags; + } + + /** + * Change the given bit of this flag. + * + * @param value the new value of given bit. + * @return this. + */ + protected F setFlag(int flag, boolean value) { + if (value) { + mFlags |= flag; + } else { + mFlags &= ~flag; + } + @SuppressWarnings("unchecked") + F f = (F) this; + return f; + } + +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/Handle.java b/mojo/public/java/src/org/chromium/mojo/system/Handle.java new file mode 100644 index 0000000..6f60055 --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/Handle.java @@ -0,0 +1,36 @@ +// 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 java.io.Closeable; + +/** + * A generic mojo handle. + */ +public interface Handle extends Closeable { + + /** + * Closes the given |handle|. + * <p> + * Concurrent operations on |handle| may succeed (or fail as usual) if they happen before the + * close, be cancelled with result |MojoResult.CANCELLED| if they properly overlap (this is + * likely the case with |wait()|, etc.), or fail with |MojoResult.INVALID_ARGUMENT| if they + * happen after. + */ + @Override + public void close(); + + /** + * @see Core#wait(Handle, Core.WaitFlags, long) + */ + public int wait(Core.WaitFlags flags, long deadline); + + /** + * @return whether the handle is valid. A handle is valid until it has been explicitly closed or + * send through a message pipe via |MessagePipeHandle.writeMessage|. + */ + public boolean isValid(); + +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/MessagePipeHandle.java b/mojo/public/java/src/org/chromium/mojo/system/MessagePipeHandle.java new file mode 100644 index 0000000..c187497 --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/MessagePipeHandle.java @@ -0,0 +1,181 @@ +// 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 java.nio.ByteBuffer; +import java.util.List; + +/** + * Message pipes are bidirectional communication channel for framed data (i.e., messages). Messages + * can contain plain data and/or Mojo handles. + */ +public interface MessagePipeHandle extends Handle { + /** + * Flags for the write operations on MessagePipeHandle . + */ + public static class WriteFlags extends Flags<WriteFlags> { + private static final int FLAG_NONE = 0; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flag. + */ + private WriteFlags(int flags) { + super(flags); + } + + /** + * @return a flag with no bit set. + */ + public static WriteFlags none() { + return new WriteFlags(FLAG_NONE); + } + } + + /** + * Flags for the read operations on MessagePipeHandle. + */ + public static class ReadFlags extends Flags<ReadFlags> { + private static final int FLAG_NONE = 0; + private static final int FLAG_MAY_DISCARD = 1 << 0; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flag. + */ + private ReadFlags(int flags) { + super(flags); + } + + /** + * Change the may-discard bit of this flag. If set, if the message is unable to be read for + * whatever reason (e.g., the caller-supplied buffer is too small), discard the message + * (i.e., simply dequeue it). + * + * @param mayDiscard the new value of the may-discard bit. + * @return this. + */ + public ReadFlags setMayDiscard(boolean mayDiscard) { + return setFlag(FLAG_MAY_DISCARD, mayDiscard); + } + + /** + * @return a flag with no bit set. + */ + public static ReadFlags none() { + return new ReadFlags(FLAG_NONE); + } + + } + + /** + * Writes a message to the message pipe endpoint, with message data specified by |bytes| and + * attached handles specified by |handles|, and options specified by |flags|. If there is no + * message data, |bytes| may be null, otherwise it must be a direct ByteBuffer. If there are no + * attached handles, |handles| may be null. + * <p> + * If handles are attached, on success the handles will no longer be valid (the receiver will + * receive equivalent, but logically different, handles). Handles to be sent should not be in + * simultaneous use (e.g., on another thread). + */ + void writeMessage(ByteBuffer bytes, List<Handle> handles, WriteFlags flags); + + /** + * Result of the |readMessage| method. + */ + public static class ReadMessageResult { + /** + * <code>true</code> if a message was read. + */ + private boolean mWasMessageRead; + /** + * If a message was read, the size in bytes of the message, otherwise the size in bytes of + * the next message. + */ + private int mMessageSize; + /** + * If a message was read, the number of handles contained in the message, otherwise the + * number of handles contained in the next message. + */ + private int mHandlesCount; + /** + * If a message was read, the handles contained in the message, undefined otherwise. + */ + private List<UntypedHandle> mHandles; + + /** + * @return the wasMessageRead + */ + public boolean getWasMessageRead() { + return mWasMessageRead; + } + + /** + * @param wasMessageRead the wasMessageRead to set + */ + public void setWasMessageRead(boolean wasMessageRead) { + mWasMessageRead = wasMessageRead; + } + + /** + * @return the messageSize + */ + public int getMessageSize() { + return mMessageSize; + } + + /** + * @param messageSize the messageSize to set + */ + public void setMessageSize(int messageSize) { + mMessageSize = messageSize; + } + + /** + * @return the handlesCount + */ + public int getHandlesCount() { + return mHandlesCount; + } + + /** + * @param handlesCount the handlesCount to set + */ + public void setHandlesCount(int handlesCount) { + mHandlesCount = handlesCount; + } + + /** + * @return the handles + */ + public List<UntypedHandle> getHandles() { + return mHandles; + } + + /** + * @param handles the handles to set + */ + public void setHandles(List<UntypedHandle> handles) { + mHandles = handles; + } + } + + /** + * Reads a message from the message pipe endpoint; also usable to query the size of the next + * message or discard the next message. |bytes| indicate the buffer/buffer size to receive the + * message data (if any) and |maxNumberOfHandles| indicate the maximum handle count to receive + * the attached handles (if any). |bytes| is optional. If null, |maxNumberOfHandles| must be + * zero, and the return value will indicate the size of the next message. If non-null, it must + * be a direct ByteBuffer and the return value will indicate if the message was read or not. If + * the message was read its content will be in |bytes|, and the attached handles will be in the + * return value. Partial reads are NEVER done. Either a full read is done and |wasMessageRead| + * will be true, or the read is NOT done and |wasMessageRead| will be false (if |mayDiscard| was + * set, the message is also discarded in this case). + */ + ReadMessageResult readMessage(ByteBuffer bytes, int maxNumberOfHandles, + ReadFlags flags); +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/MojoException.java b/mojo/public/java/src/org/chromium/mojo/system/MojoException.java new file mode 100644 index 0000000..e06f647 --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/MojoException.java @@ -0,0 +1,36 @@ +// 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; + +/** + * Exception for the core mojo API. + */ +public class MojoException extends RuntimeException { + + private final int mCode; + + /** + * Constructor. + */ + public MojoException(int code) { + mCode = code; + } + + /** + * The mojo result code associated with this exception. See {@link MojoResult} for possible + * values. + */ + public int getMojoResult() { + return mCode; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "MojoResult(" + mCode + "): " + MojoResult.describe(mCode); + } +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/MojoResult.java b/mojo/public/java/src/org/chromium/mojo/system/MojoResult.java new file mode 100644 index 0000000..a829c833 --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/MojoResult.java @@ -0,0 +1,82 @@ +// 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; + +/** + * The different mojo result codes. + */ +public final class MojoResult { + public static final int OK = 0; + public static final int CANCELLED = -1; + public static final int UNKNOWN = -2; + public static final int INVALID_ARGUMENT = -3; + public static final int DEADLINE_EXCEEDED = -4; + public static final int NOT_FOUND = -5; + public static final int ALREADY_EXISTS = -6; + public static final int PERMISSION_DENIED = -7; + public static final int RESOURCE_EXHAUSTED = -8; + public static final int FAILED_PRECONDITION = -9; + public static final int ABORTED = -10; + public static final int OUT_OF_RANGE = -11; + public static final int UNIMPLEMENTED = -12; + public static final int INTERNAL = -13; + public static final int UNAVAILABLE = -14; + public static final int DATA_LOSS = -15; + public static final int BUSY = -16; + public static final int SHOULD_WAIT = -17; + + /** + * never instantiate. + */ + private MojoResult() { + } + + /** + * Describes the given result code. + */ + public static String describe(int mCode) { + switch (mCode) { + case OK: + return "OK"; + case CANCELLED: + return "CANCELLED"; + case UNKNOWN: + return "UNKNOWN"; + case INVALID_ARGUMENT: + return "INVALID_ARGUMENT"; + case DEADLINE_EXCEEDED: + return "DEADLINE_EXCEEDED"; + case NOT_FOUND: + return "NOT_FOUND"; + case ALREADY_EXISTS: + return "ALREADY_EXISTS"; + case PERMISSION_DENIED: + return "PERMISSION_DENIED"; + case RESOURCE_EXHAUSTED: + return "RESOURCE_EXHAUSTED"; + case FAILED_PRECONDITION: + return "FAILED_PRECONDITION"; + case ABORTED: + return "ABORTED"; + case OUT_OF_RANGE: + return "OUT_OF_RANGE"; + case UNIMPLEMENTED: + return "UNIMPLEMENTED"; + case INTERNAL: + return "INTERNAL"; + case UNAVAILABLE: + return "UNAVAILABLE"; + case DATA_LOSS: + return "DATA_LOSS"; + case BUSY: + return "BUSY"; + case SHOULD_WAIT: + return "SHOULD_WAIT"; + default: + return "UNKNOWN"; + } + + } +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/Pair.java b/mojo/public/java/src/org/chromium/mojo/system/Pair.java new file mode 100644 index 0000000..c302aed --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/Pair.java @@ -0,0 +1,61 @@ +// 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 java.util.Objects; + +/** + * A pair of object. + * + * @param <F> Type of the first element. + * @param <S> Type of the second element. + */ +public class Pair<F, S> { + + public final F first; + public final S second; + + /** + * Dedicated constructor. + * + * @param first the first element of the pair. + * @param second the second element of the pair. + */ + public Pair(F first, S second) { + this.first = first; + this.second = second; + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Pair)) { + return false; + } + Pair<?, ?> p = (Pair<?, ?>) o; + return Objects.equals(p.first, first) && Objects.equals(p.second, second); + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); + } + + /** + * Helper method for creating a pair. + * + * @param a the first element of the pair. + * @param b the second element of the pair. + * @return the pair containing a and b. + */ + public static <A, B, C extends A, D extends B> Pair<A, B> create(C a, D b) { + return new Pair<A, B>(a, b); + } +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/SharedBufferHandle.java b/mojo/public/java/src/org/chromium/mojo/system/SharedBufferHandle.java new file mode 100644 index 0000000..908db9e --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/SharedBufferHandle.java @@ -0,0 +1,139 @@ +// 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 java.nio.ByteBuffer; + +/** + * A buffer that can be shared between applications. + */ +public interface SharedBufferHandle extends Handle { + + /** + * Flags for the shared buffer creation operation. + */ + public static class CreateFlags extends Flags<CreateFlags> { + private static final int FLAG_NONE = 0; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flags. + */ + protected CreateFlags(int flags) { + super(flags); + } + + /** + * @return flags with no bit set. + */ + public static CreateFlags none() { + return new CreateFlags(FLAG_NONE); + } + + } + + /** + * Used to specify creation parameters for a shared buffer to |Core#createSharedBuffer()|. + */ + public static class CreateOptions { + private CreateFlags mFlags = CreateFlags.none(); + + /** + * @return the flags + */ + public CreateFlags getFlags() { + return mFlags; + } + + } + + /** + * Flags for the shared buffer duplication operation. + */ + public static class DuplicateFlags extends Flags<DuplicateFlags> { + private static final int FLAG_NONE = 0; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flags. + */ + protected DuplicateFlags(int flags) { + super(flags); + } + + /** + * @return flags with no bit set. + */ + public static DuplicateFlags none() { + return new DuplicateFlags(FLAG_NONE); + } + + } + + /** + * Used to specify parameters in duplicating access to a shared buffer to + * |SharedBufferHandle#duplicate| + */ + public static class DuplicateOptions { + private DuplicateFlags mFlags = DuplicateFlags.none(); + + /** + * @return the flags + */ + public DuplicateFlags getFlags() { + return mFlags; + } + + } + + /** + * TODO(qsr): Insert description here. + */ + public static class MapFlags extends Flags<MapFlags> { + private static final int FLAG_NONE = 0; + + /** + * Dedicated constructor. + * + * @param flags initial value of the flags. + */ + protected MapFlags(int flags) { + super(flags); + } + + /** + * @return flags with no bit set. + */ + public static MapFlags none() { + return new MapFlags(FLAG_NONE); + } + + } + + /** + * Duplicates the handle. This creates another handle (returned on success), which can then be + * sent to another application over a message pipe, while retaining access to this handle (and + * any mappings that it may have). + */ + public SharedBufferHandle duplicate(DuplicateOptions options); + + /** + * Map the part (at offset |offset| of length |numBytes|) of the buffer given by this handle + * into memory. |offset + numBytes| must be less than or equal to the size of the buffer. On + * success, the returned buffer points to memory with the requested part of the buffer. A single + * buffer handle may have multiple active mappings (possibly depending on the buffer type). The + * permissions (e.g., writable or executable) of the returned memory may depend on the + * properties of the buffer and properties attached to the buffer handle as well as |flags|. + */ + public ByteBuffer map(long offset, long numBytes, MapFlags flags); + + /** + * Unmap a buffer pointer that was mapped by |map()|. + */ + public void unmap(ByteBuffer buffer); + +} diff --git a/mojo/public/java/src/org/chromium/mojo/system/UntypedHandle.java b/mojo/public/java/src/org/chromium/mojo/system/UntypedHandle.java new file mode 100644 index 0000000..63b5f7c --- /dev/null +++ b/mojo/public/java/src/org/chromium/mojo/system/UntypedHandle.java @@ -0,0 +1,41 @@ +// 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; + + +/** + * TODO(qsr): Insert description here. + */ +public interface UntypedHandle extends Handle { + + /** + * TODO(qsr): + * + * @return TODO(qsr) + */ + public MessagePipeHandle toMessagePipeHandle(); + + /** + * TODO(qsr): + * + * @return TODO(qsr) + */ + public DataPipe.ConsumerHandle toDataPipeConsumerHandle(); + + /** + * TODO(qsr): + * + * @return TODO(qsr) + */ + public DataPipe.ProducerHandle toDataPipeProducerHandle(); + + /** + * TODO(qsr): + * + * @return TODO(qsr) + */ + public SharedBufferHandle toSharedBufferHandle(); + +} |