// 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 #include #include "base/android/jni_android.h" #include "base/android/jni_array.h" #include "base/android/scoped_java_ref.h" #include "jni/CoreImpl_jni.h" #include "mojo/public/c/system/core.h" #include "mojo/public/cpp/system/message_pipe.h" namespace mojo { namespace android { using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; static jlong JNI_CoreImpl_GetTimeTicksNow( JNIEnv* env, const JavaParamRef& jcaller) { return MojoGetTimeTicksNow(); } static ScopedJavaLocalRef JNI_CoreImpl_CreateMessagePipe( JNIEnv* env, const JavaParamRef& jcaller, const JavaParamRef& options_buffer) { const MojoCreateMessagePipeOptions* options = NULL; if (options_buffer) { const void* buffer_start = env->GetDirectBufferAddress(options_buffer); DCHECK(buffer_start); DCHECK_EQ(reinterpret_cast(buffer_start) % 8, 0u); const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer); DCHECK_EQ(buffer_size, sizeof(MojoCreateMessagePipeOptions)); options = static_cast(buffer_start); DCHECK_EQ(options->struct_size, buffer_size); } MojoHandle handle1; MojoHandle handle2; MojoResult result = MojoCreateMessagePipe(options, &handle1, &handle2); return Java_CoreImpl_newNativeCreationResult(env, result, handle1, handle2); } static ScopedJavaLocalRef JNI_CoreImpl_CreateDataPipe( JNIEnv* env, const JavaParamRef& jcaller, const JavaParamRef& options_buffer) { const MojoCreateDataPipeOptions* options = NULL; if (options_buffer) { const void* buffer_start = env->GetDirectBufferAddress(options_buffer); DCHECK(buffer_start); DCHECK_EQ(reinterpret_cast(buffer_start) % 8, 0u); const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer); DCHECK_EQ(buffer_size, sizeof(MojoCreateDataPipeOptions)); options = static_cast(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); } static ScopedJavaLocalRef JNI_CoreImpl_CreateSharedBuffer( JNIEnv* env, const JavaParamRef& jcaller, const JavaParamRef& options_buffer, jlong num_bytes) { const MojoCreateSharedBufferOptions* options = 0; if (options_buffer) { const void* buffer_start = env->GetDirectBufferAddress(options_buffer); DCHECK(buffer_start); DCHECK_EQ(reinterpret_cast(buffer_start) % 8, 0u); const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer); DCHECK_EQ(buffer_size, sizeof(MojoCreateSharedBufferOptions)); options = static_cast(buffer_start); DCHECK_EQ(options->struct_size, buffer_size); } MojoHandle handle; MojoResult result = MojoCreateSharedBuffer(num_bytes, options, &handle); return Java_CoreImpl_newResultAndInteger(env, result, handle); } static jint JNI_CoreImpl_Close(JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle) { return MojoClose(mojo_handle); } static jint JNI_CoreImpl_QueryHandleSignalsState( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, const JavaParamRef& buffer) { MojoHandleSignalsState* signals_state = static_cast(env->GetDirectBufferAddress(buffer)); DCHECK(signals_state); DCHECK_EQ(sizeof(MojoHandleSignalsState), static_cast(env->GetDirectBufferCapacity(buffer))); return MojoQueryHandleSignalsState(mojo_handle, signals_state); } static jint JNI_CoreImpl_WriteMessage( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, const JavaParamRef& bytes, jint num_bytes, const JavaParamRef& 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(env->GetDirectBufferAddress(handles_buffer)); num_handles = env->GetDirectBufferCapacity(handles_buffer) / 4; } // Java code will handle invalidating handles if the write succeeded. return WriteMessageRaw( MessagePipeHandle(static_cast(mojo_handle)), buffer_start, buffer_size, handles, num_handles, flags); } static ScopedJavaLocalRef JNI_CoreImpl_ReadMessage( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jint flags) { ScopedMessageHandle message; MojoResult result = ReadMessageNew(MessagePipeHandle(mojo_handle), &message, flags); if (result != MOJO_RESULT_OK) return Java_CoreImpl_newReadMessageResult(env, result, nullptr, nullptr); DCHECK(message.is_valid()); result = MojoSerializeMessage(message->value(), nullptr); if (result != MOJO_RESULT_OK && result != MOJO_RESULT_FAILED_PRECONDITION) { return Java_CoreImpl_newReadMessageResult(env, MOJO_RESULT_ABORTED, nullptr, nullptr); } uint32_t num_bytes; void* buffer; uint32_t num_handles = 0; std::vector handles; result = MojoGetMessageData(message->value(), nullptr, &buffer, &num_bytes, nullptr, &num_handles); if (result == MOJO_RESULT_RESOURCE_EXHAUSTED) { handles.resize(num_handles); result = MojoGetMessageData(message->value(), nullptr, &buffer, &num_bytes, handles.data(), &num_handles); } if (result != MOJO_RESULT_OK) return Java_CoreImpl_newReadMessageResult(env, result, nullptr, nullptr); return Java_CoreImpl_newReadMessageResult( env, result, base::android::ToJavaByteArray(env, static_cast(buffer), num_bytes), base::android::ToJavaIntArray( env, reinterpret_cast(handles.data()), num_handles)); } static ScopedJavaLocalRef JNI_CoreImpl_ReadData( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, const JavaParamRef& 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)); } MojoReadDataOptions options; options.struct_size = sizeof(options); options.flags = flags; MojoResult result = MojoReadData(mojo_handle, &options, buffer_start, &buffer_size); return Java_CoreImpl_newResultAndInteger( env, result, (result == MOJO_RESULT_OK) ? buffer_size : 0); } static ScopedJavaLocalRef JNI_CoreImpl_BeginReadData( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jint num_bytes, jint flags) { void const* buffer = 0; uint32_t buffer_size = num_bytes; MojoBeginReadDataOptions options; options.struct_size = sizeof(options); options.flags = flags; MojoResult result = MojoBeginReadData(mojo_handle, &options, &buffer, &buffer_size); if (result == MOJO_RESULT_OK) { ScopedJavaLocalRef byte_buffer( env, env->NewDirectByteBuffer(const_cast(buffer), buffer_size)); return Java_CoreImpl_newResultAndBuffer(env, result, byte_buffer); } else { return Java_CoreImpl_newResultAndBuffer(env, result, nullptr); } } static jint JNI_CoreImpl_EndReadData(JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jint num_bytes_read) { return MojoEndReadData(mojo_handle, num_bytes_read, nullptr); } static ScopedJavaLocalRef JNI_CoreImpl_WriteData( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, const JavaParamRef& elements, jint limit, jint flags) { void* buffer_start = env->GetDirectBufferAddress(elements); DCHECK(buffer_start); DCHECK(limit <= env->GetDirectBufferCapacity(elements)); uint32_t buffer_size = limit; MojoWriteDataOptions options; options.struct_size = sizeof(options); options.flags = flags; MojoResult result = MojoWriteData(mojo_handle, buffer_start, &buffer_size, &options); return Java_CoreImpl_newResultAndInteger( env, result, (result == MOJO_RESULT_OK) ? buffer_size : 0); } static ScopedJavaLocalRef JNI_CoreImpl_BeginWriteData( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jint num_bytes, jint flags) { void* buffer = 0; uint32_t buffer_size = num_bytes; MojoBeginWriteDataOptions options; options.struct_size = sizeof(options); options.flags = flags; MojoResult result = MojoBeginWriteData(mojo_handle, &options, &buffer, &buffer_size); if (result == MOJO_RESULT_OK) { ScopedJavaLocalRef byte_buffer( env, env->NewDirectByteBuffer(buffer, buffer_size)); return Java_CoreImpl_newResultAndBuffer(env, result, byte_buffer); } else { return Java_CoreImpl_newResultAndBuffer(env, result, nullptr); } } static jint JNI_CoreImpl_EndWriteData(JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jint num_bytes_written) { return MojoEndWriteData(mojo_handle, num_bytes_written, nullptr); } static ScopedJavaLocalRef JNI_CoreImpl_Duplicate( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, const JavaParamRef& 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(buffer_start); DCHECK_EQ(options->struct_size, buffer_size); } MojoHandle handle; MojoResult result = MojoDuplicateBufferHandle(mojo_handle, options, &handle); return Java_CoreImpl_newResultAndInteger(env, result, handle); } static ScopedJavaLocalRef JNI_CoreImpl_Map( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jlong offset, jlong num_bytes, jint flags) { void* buffer = 0; MojoMapBufferOptions options; options.struct_size = sizeof(options); options.flags = flags; MojoResult result = MojoMapBuffer(mojo_handle, offset, num_bytes, &options, &buffer); if (result == MOJO_RESULT_OK) { ScopedJavaLocalRef byte_buffer( env, env->NewDirectByteBuffer(buffer, num_bytes)); return Java_CoreImpl_newResultAndBuffer(env, result, byte_buffer); } else { return Java_CoreImpl_newResultAndBuffer(env, result, nullptr); } } static int JNI_CoreImpl_Unmap(JNIEnv* env, const JavaParamRef& jcaller, const JavaParamRef& buffer) { void* buffer_start = env->GetDirectBufferAddress(buffer); DCHECK(buffer_start); return MojoUnmapBuffer(buffer_start); } static jint JNI_CoreImpl_GetNativeBufferOffset( JNIEnv* env, const JavaParamRef& jcaller, const JavaParamRef& buffer, jint alignment) { jint offset = reinterpret_cast(env->GetDirectBufferAddress(buffer)) % alignment; if (offset == 0) return 0; return alignment - offset; } } // namespace android } // namespace mojo