summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authorqsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-23 16:02:32 +0000
committerqsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-23 16:02:32 +0000
commit70c0364a44341bf10c5157c11d3689a3cf7c6054 (patch)
tree201dff677afe4bb771b89f370a4c93ee5e276305 /mojo
parent76b34ffc13b9d895f60e20a752f5d09317d00db0 (diff)
downloadchromium_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')
-rw-r--r--mojo/android/DEPS3
-rw-r--r--mojo/android/javatests/AndroidManifest.xml21
-rw-r--r--mojo/android/javatests/apk/EMPTY0
-rw-r--r--mojo/android/javatests/core_test.cc26
-rw-r--r--mojo/android/javatests/core_test.h20
-rw-r--r--mojo/android/javatests/init_library.cc40
-rw-r--r--mojo/android/javatests/src/org/chromium/mojo/system/CoreTest.java471
-rw-r--r--mojo/android/system/core_impl.cc293
-rw-r--r--mojo/android/system/core_impl.h20
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/CoreImpl.java584
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/CoreSingleton.java18
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/DataPipeConsumerHandleImpl.java63
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/DataPipeProducerHandleImpl.java55
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/HandleImpl.java112
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/MessagePipeHandleImpl.java47
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/SharedBufferHandleImpl.java52
-rw-r--r--mojo/android/system/src/org/chromium/mojo/system/UntypedHandleImpl.java54
-rw-r--r--mojo/mojo.gyp99
-rw-r--r--mojo/mojo_public.gypi14
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/Core.java178
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/DataPipe.java308
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/Flags.java48
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/Handle.java36
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/MessagePipeHandle.java181
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/MojoException.java36
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/MojoResult.java82
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/Pair.java61
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/SharedBufferHandle.java139
-rw-r--r--mojo/public/java/src/org/chromium/mojo/system/UntypedHandle.java41
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();
+
+}