// 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 #include #include #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/android/scoped_java_ref.h" #include "base/bind.h" #include "base/location.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "jni/CoreImpl_jni.h" #include "mojo/message_pump/handle_watcher.h" #include "mojo/public/c/system/core.h" namespace { using MojoAsyncWaitID = uintptr_t; const MojoAsyncWaitID kInvalidHandleCancelID = 0; struct AsyncWaitCallbackData { base::android::ScopedJavaGlobalRef core_impl; base::android::ScopedJavaGlobalRef callback; base::android::ScopedJavaGlobalRef cancellable; AsyncWaitCallbackData(JNIEnv* env, jobject core_impl, jobject callback) { this->core_impl.Reset(env, core_impl); this->callback.Reset(env, callback); } }; void AsyncWaitCallback(mojo::common::HandleWatcher* watcher, void* data, MojoResult result) { delete watcher; std::unique_ptr callback_data( static_cast(data)); mojo::android::Java_CoreImpl_onAsyncWaitResult( base::android::AttachCurrentThread(), callback_data->core_impl.obj(), result, callback_data->callback.obj(), callback_data->cancellable.obj()); } } // namespace namespace mojo { namespace android { static jlong GetTimeTicksNow(JNIEnv* env, const JavaParamRef& jcaller) { return MojoGetTimeTicksNow(); } static jint WaitMany(JNIEnv* env, const JavaParamRef& jcaller, const JavaParamRef& buffer, jlong deadline) { // |buffer| contains, in this order // input: The array of N handles (MojoHandle, 4 bytes each) // input: The array of N signals (MojoHandleSignals, 4 bytes each) // space for output: The array of N handle states (MojoHandleSignalsState, 8 // bytes each) // space for output: The result index (uint32_t, 4 bytes) uint8_t* buffer_start = static_cast(env->GetDirectBufferAddress(buffer)); DCHECK(buffer_start); DCHECK_EQ(reinterpret_cast(buffer_start) % 8, 0u); // Each handle of the input array contributes 4 (MojoHandle) + 4 // (MojoHandleSignals) + 8 (MojoHandleSignalsState) = 16 bytes to the size of // the buffer. const size_t size_per_handle = 16; const size_t buffer_size = env->GetDirectBufferCapacity(buffer); DCHECK_EQ((buffer_size - 4) % size_per_handle, 0u); const size_t nb_handles = (buffer_size - 4) / size_per_handle; const MojoHandle* handle_start = reinterpret_cast(buffer_start); const MojoHandleSignals* signals_start = reinterpret_cast(buffer_start + 4 * nb_handles); MojoHandleSignalsState* states_start = reinterpret_cast(buffer_start + 8 * nb_handles); uint32_t* result_index = reinterpret_cast(buffer_start + 16 * nb_handles); *result_index = static_cast(-1); return MojoWaitMany(handle_start, signals_start, nb_handles, deadline, result_index, states_start); } static ScopedJavaLocalRef 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 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 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(options, num_bytes, &handle); return Java_CoreImpl_newResultAndInteger(env, result, handle); } static jint Close(JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle) { return MojoClose(mojo_handle); } static jint Wait(JNIEnv* env, const JavaParamRef& jcaller, const JavaParamRef& buffer, jint mojo_handle, jint signals, jlong deadline) { // Buffer contains space for the MojoHandleSignalsState void* buffer_start = env->GetDirectBufferAddress(buffer); DCHECK(buffer_start); DCHECK_EQ(reinterpret_cast(buffer_start) % 8, 0u); DCHECK_EQ(sizeof(struct MojoHandleSignalsState), static_cast(env->GetDirectBufferCapacity(buffer))); struct MojoHandleSignalsState* signals_state = static_cast(buffer_start); return MojoWait(mojo_handle, signals, deadline, signals_state); } static jint 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 MojoWriteMessage( mojo_handle, buffer_start, buffer_size, handles, num_handles, flags); } static ScopedJavaLocalRef ReadMessage( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, const JavaParamRef& bytes, const JavaParamRef& 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(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_newReadMessageResult(env, result, buffer_size, num_handles); } static ScopedJavaLocalRef 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)); } MojoResult result = MojoReadData(mojo_handle, buffer_start, &buffer_size, flags); return Java_CoreImpl_newResultAndInteger( env, result, (result == MOJO_RESULT_OK) ? buffer_size : 0); } static ScopedJavaLocalRef BeginReadData( JNIEnv* env, const JavaParamRef& 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(buffer), buffer_size); } return Java_CoreImpl_newResultAndBuffer(env, result, byte_buffer); } static jint EndReadData(JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jint num_bytes_read) { return MojoEndReadData(mojo_handle, num_bytes_read); } static ScopedJavaLocalRef 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; MojoResult result = MojoWriteData(mojo_handle, buffer_start, &buffer_size, flags); return Java_CoreImpl_newResultAndInteger( env, result, (result == MOJO_RESULT_OK) ? buffer_size : 0); } static ScopedJavaLocalRef BeginWriteData( JNIEnv* env, const JavaParamRef& 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_newResultAndBuffer(env, result, byte_buffer); } static jint EndWriteData(JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jint num_bytes_written) { return MojoEndWriteData(mojo_handle, num_bytes_written); } static ScopedJavaLocalRef 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 Map(JNIEnv* env, const JavaParamRef& 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_newResultAndBuffer(env, result, byte_buffer); } static int Unmap(JNIEnv* env, const JavaParamRef& jcaller, const JavaParamRef& buffer) { void* buffer_start = env->GetDirectBufferAddress(buffer); DCHECK(buffer_start); return MojoUnmapBuffer(buffer_start); } static ScopedJavaLocalRef AsyncWait( JNIEnv* env, const JavaParamRef& jcaller, jint mojo_handle, jint signals, jlong deadline, const JavaParamRef& callback) { AsyncWaitCallbackData* callback_data = new AsyncWaitCallbackData(env, jcaller, callback); MojoAsyncWaitID cancel_id; if (static_cast(mojo_handle) != MOJO_HANDLE_INVALID) { common::HandleWatcher* watcher = new common::HandleWatcher(); cancel_id = reinterpret_cast(watcher); watcher->Start(Handle(static_cast(mojo_handle)), signals, deadline, base::Bind(&AsyncWaitCallback, watcher, callback_data)); } else { cancel_id = kInvalidHandleCancelID; base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&AsyncWaitCallback, nullptr, callback_data, MOJO_RESULT_INVALID_ARGUMENT)); } base::android::ScopedJavaLocalRef cancellable = Java_CoreImpl_newAsyncWaiterCancellableImpl( env, jcaller, cancel_id, reinterpret_cast(callback_data)); callback_data->cancellable.Reset(env, cancellable.obj()); return cancellable; } static void CancelAsyncWait(JNIEnv* env, const JavaParamRef& jcaller, jlong id, jlong data_ptr) { if (id == 0) { // If |id| is |kInvalidHandleCancelID|, the async wait was done on an // invalid handle, so the AsyncWaitCallback will be called and will clear // the data_ptr. return; } std::unique_ptr deleter( reinterpret_cast(data_ptr)); delete reinterpret_cast( static_cast(id)); } static jint 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; } bool RegisterCoreImpl(JNIEnv* env) { return RegisterNativesImpl(env); } } // namespace android } // namespace mojo