1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/android/system/core_impl.h"
6
7#include "base/android/base_jni_registrar.h"
8#include "base/android/jni_android.h"
9#include "base/android/jni_registrar.h"
10#include "base/android/library_loader/library_loader_hooks.h"
11#include "base/android/scoped_java_ref.h"
12#include "base/bind.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/message_loop/message_loop.h"
15#include "jni/CoreImpl_jni.h"
16#include "mojo/public/c/environment/async_waiter.h"
17#include "mojo/public/c/system/core.h"
18#include "mojo/public/cpp/environment/environment.h"
19
20namespace {
21
22// |AsyncWait| is guaranteed never to return 0.
23const MojoAsyncWaitID kInvalidHandleCancelID = 0;
24
25struct AsyncWaitCallbackData {
26  base::android::ScopedJavaGlobalRef<jobject> core_impl;
27  base::android::ScopedJavaGlobalRef<jobject> callback;
28  base::android::ScopedJavaGlobalRef<jobject> cancellable;
29
30  AsyncWaitCallbackData(JNIEnv* env, jobject core_impl, jobject callback) {
31    this->core_impl.Reset(env, core_impl);
32    this->callback.Reset(env, callback);
33  }
34};
35
36void AsyncWaitCallback(void* data, MojoResult result) {
37  scoped_ptr<AsyncWaitCallbackData> callback_data(
38      static_cast<AsyncWaitCallbackData*>(data));
39  mojo::android::Java_CoreImpl_onAsyncWaitResult(
40      base::android::AttachCurrentThread(),
41      callback_data->core_impl.obj(),
42      result,
43      callback_data->callback.obj(),
44      callback_data->cancellable.obj());
45}
46
47}  // namespace
48
49namespace mojo {
50namespace android {
51
52static jlong GetTimeTicksNow(JNIEnv* env, jobject jcaller) {
53  return MojoGetTimeTicksNow();
54}
55
56static jint WaitMany(JNIEnv* env,
57                     jobject jcaller,
58                     jobject buffer,
59                     jlong deadline) {
60  // Buffer contains first the list of handles, then the list of signals.
61  const void* buffer_start = env->GetDirectBufferAddress(buffer);
62  DCHECK(buffer_start);
63  DCHECK_EQ(reinterpret_cast<const uintptr_t>(buffer_start) % 8, 0u);
64  const size_t record_size = 8;
65  const size_t buffer_size = env->GetDirectBufferCapacity(buffer);
66  DCHECK_EQ(buffer_size % record_size, 0u);
67
68  const size_t nb_handles = buffer_size / record_size;
69  const MojoHandle* handle_start = static_cast<const MojoHandle*>(buffer_start);
70  const MojoHandleSignals* signals_start =
71      static_cast<const MojoHandleSignals*>(handle_start + nb_handles);
72  return MojoWaitMany(handle_start, signals_start, nb_handles, deadline);
73}
74
75static jobject CreateMessagePipe(JNIEnv* env,
76                                 jobject jcaller,
77                                 jobject options_buffer) {
78  const MojoCreateMessagePipeOptions* options = NULL;
79  if (options_buffer) {
80    const void* buffer_start = env->GetDirectBufferAddress(options_buffer);
81    DCHECK(buffer_start);
82    DCHECK_EQ(reinterpret_cast<const uintptr_t>(buffer_start) % 8, 0u);
83    const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer);
84    DCHECK_EQ(buffer_size, sizeof(MojoCreateMessagePipeOptions));
85    options = static_cast<const MojoCreateMessagePipeOptions*>(buffer_start);
86    DCHECK_EQ(options->struct_size, buffer_size);
87  }
88  MojoHandle handle1;
89  MojoHandle handle2;
90  MojoResult result = MojoCreateMessagePipe(options, &handle1, &handle2);
91  return Java_CoreImpl_newNativeCreationResult(env, result, handle1, handle2)
92      .Release();
93}
94
95static jobject CreateDataPipe(JNIEnv* env,
96                              jobject jcaller,
97                              jobject options_buffer) {
98  const MojoCreateDataPipeOptions* options = NULL;
99  if (options_buffer) {
100    const void* buffer_start = env->GetDirectBufferAddress(options_buffer);
101    DCHECK(buffer_start);
102    DCHECK_EQ(reinterpret_cast<const uintptr_t>(buffer_start) % 8, 0u);
103    const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer);
104    DCHECK_EQ(buffer_size, sizeof(MojoCreateDataPipeOptions));
105    options = static_cast<const MojoCreateDataPipeOptions*>(buffer_start);
106    DCHECK_EQ(options->struct_size, buffer_size);
107  }
108  MojoHandle handle1;
109  MojoHandle handle2;
110  MojoResult result = MojoCreateDataPipe(options, &handle1, &handle2);
111  return Java_CoreImpl_newNativeCreationResult(env, result, handle1, handle2)
112      .Release();
113}
114
115static jobject CreateSharedBuffer(JNIEnv* env,
116                                  jobject jcaller,
117                                  jobject options_buffer,
118                                  jlong num_bytes) {
119  const MojoCreateSharedBufferOptions* options = 0;
120  if (options_buffer) {
121    const void* buffer_start = env->GetDirectBufferAddress(options_buffer);
122    DCHECK(buffer_start);
123    DCHECK_EQ(reinterpret_cast<const uintptr_t>(buffer_start) % 8, 0u);
124    const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer);
125    DCHECK_EQ(buffer_size, sizeof(MojoCreateSharedBufferOptions));
126    options = static_cast<const MojoCreateSharedBufferOptions*>(buffer_start);
127    DCHECK_EQ(options->struct_size, buffer_size);
128  }
129  MojoHandle handle;
130  MojoResult result = MojoCreateSharedBuffer(options, num_bytes, &handle);
131  return Java_CoreImpl_newNativeCreationResult(env, result, handle, 0)
132      .Release();
133}
134
135static jint Close(JNIEnv* env, jobject jcaller, jint mojo_handle) {
136  return MojoClose(mojo_handle);
137}
138
139static jint Wait(JNIEnv* env,
140                 jobject jcaller,
141                 jint mojo_handle,
142                 jint signals,
143                 jlong deadline) {
144  return MojoWait(mojo_handle, signals, deadline);
145}
146
147static jint WriteMessage(JNIEnv* env,
148                         jobject jcaller,
149                         jint mojo_handle,
150                         jobject bytes,
151                         jint num_bytes,
152                         jobject handles_buffer,
153                         jint flags) {
154  const void* buffer_start = 0;
155  uint32_t buffer_size = 0;
156  if (bytes) {
157    buffer_start = env->GetDirectBufferAddress(bytes);
158    DCHECK(buffer_start);
159    DCHECK(env->GetDirectBufferCapacity(bytes) >= num_bytes);
160    buffer_size = num_bytes;
161  }
162  const MojoHandle* handles = 0;
163  uint32_t num_handles = 0;
164  if (handles_buffer) {
165    handles =
166        static_cast<MojoHandle*>(env->GetDirectBufferAddress(handles_buffer));
167    num_handles = env->GetDirectBufferCapacity(handles_buffer) / 4;
168  }
169  // Java code will handle invalidating handles if the write succeeded.
170  return MojoWriteMessage(
171      mojo_handle, buffer_start, buffer_size, handles, num_handles, flags);
172}
173
174static jobject ReadMessage(JNIEnv* env,
175                           jobject jcaller,
176                           jint mojo_handle,
177                           jobject bytes,
178                           jobject handles_buffer,
179                           jint flags) {
180  void* buffer_start = 0;
181  uint32_t buffer_size = 0;
182  if (bytes) {
183    buffer_start = env->GetDirectBufferAddress(bytes);
184    DCHECK(buffer_start);
185    buffer_size = env->GetDirectBufferCapacity(bytes);
186  }
187  MojoHandle* handles = 0;
188  uint32_t num_handles = 0;
189  if (handles_buffer) {
190    handles =
191        static_cast<MojoHandle*>(env->GetDirectBufferAddress(handles_buffer));
192    num_handles = env->GetDirectBufferCapacity(handles_buffer) / 4;
193  }
194  MojoResult result = MojoReadMessage(
195      mojo_handle, buffer_start, &buffer_size, handles, &num_handles, flags);
196  // Jave code will handle taking ownership of any received handle.
197  return Java_CoreImpl_newReadMessageResult(
198             env, result, buffer_size, num_handles).Release();
199}
200
201static jint ReadData(JNIEnv* env,
202                     jobject jcaller,
203                     jint mojo_handle,
204                     jobject elements,
205                     jint elements_capacity,
206                     jint flags) {
207  void* buffer_start = 0;
208  uint32_t buffer_size = elements_capacity;
209  if (elements) {
210    buffer_start = env->GetDirectBufferAddress(elements);
211    DCHECK(buffer_start);
212    DCHECK(elements_capacity <= env->GetDirectBufferCapacity(elements));
213  }
214  MojoResult result =
215      MojoReadData(mojo_handle, buffer_start, &buffer_size, flags);
216  if (result < 0) {
217    return result;
218  }
219  return buffer_size;
220}
221
222static jobject BeginReadData(JNIEnv* env,
223                             jobject jcaller,
224                             jint mojo_handle,
225                             jint num_bytes,
226                             jint flags) {
227  void const* buffer = 0;
228  uint32_t buffer_size = num_bytes;
229  MojoResult result =
230      MojoBeginReadData(mojo_handle, &buffer, &buffer_size, flags);
231  jobject byte_buffer = 0;
232  if (result == MOJO_RESULT_OK) {
233    byte_buffer =
234        env->NewDirectByteBuffer(const_cast<void*>(buffer), buffer_size);
235  }
236  return Java_CoreImpl_newNativeCodeAndBufferResult(env, result, byte_buffer)
237      .Release();
238}
239
240static jint EndReadData(JNIEnv* env,
241                        jobject jcaller,
242                        jint mojo_handle,
243                        jint num_bytes_read) {
244  return MojoEndReadData(mojo_handle, num_bytes_read);
245}
246
247static jint WriteData(JNIEnv* env,
248                      jobject jcaller,
249                      jint mojo_handle,
250                      jobject elements,
251                      jint limit,
252                      jint flags) {
253  void* buffer_start = env->GetDirectBufferAddress(elements);
254  DCHECK(buffer_start);
255  DCHECK(limit <= env->GetDirectBufferCapacity(elements));
256  uint32_t buffer_size = limit;
257  MojoResult result =
258      MojoWriteData(mojo_handle, buffer_start, &buffer_size, flags);
259  if (result < 0) {
260    return result;
261  }
262  return buffer_size;
263}
264
265static jobject BeginWriteData(JNIEnv* env,
266                              jobject jcaller,
267                              jint mojo_handle,
268                              jint num_bytes,
269                              jint flags) {
270  void* buffer = 0;
271  uint32_t buffer_size = num_bytes;
272  MojoResult result =
273      MojoBeginWriteData(mojo_handle, &buffer, &buffer_size, flags);
274  jobject byte_buffer = 0;
275  if (result == MOJO_RESULT_OK) {
276    byte_buffer = env->NewDirectByteBuffer(buffer, buffer_size);
277  }
278  return Java_CoreImpl_newNativeCodeAndBufferResult(env, result, byte_buffer)
279      .Release();
280}
281
282static jint EndWriteData(JNIEnv* env,
283                         jobject jcaller,
284                         jint mojo_handle,
285                         jint num_bytes_written) {
286  return MojoEndWriteData(mojo_handle, num_bytes_written);
287}
288
289static jobject Duplicate(JNIEnv* env,
290                         jobject jcaller,
291                         jint mojo_handle,
292                         jobject options_buffer) {
293  const MojoDuplicateBufferHandleOptions* options = 0;
294  if (options_buffer) {
295    const void* buffer_start = env->GetDirectBufferAddress(options_buffer);
296    DCHECK(buffer_start);
297    const size_t buffer_size = env->GetDirectBufferCapacity(options_buffer);
298    DCHECK_EQ(buffer_size, sizeof(MojoDuplicateBufferHandleOptions));
299    options =
300        static_cast<const MojoDuplicateBufferHandleOptions*>(buffer_start);
301    DCHECK_EQ(options->struct_size, buffer_size);
302  }
303  MojoHandle handle;
304  MojoResult result = MojoDuplicateBufferHandle(mojo_handle, options, &handle);
305  return Java_CoreImpl_newNativeCreationResult(env, result, handle, 0)
306      .Release();
307}
308
309static jobject Map(JNIEnv* env,
310                   jobject jcaller,
311                   jint mojo_handle,
312                   jlong offset,
313                   jlong num_bytes,
314                   jint flags) {
315  void* buffer = 0;
316  MojoResult result =
317      MojoMapBuffer(mojo_handle, offset, num_bytes, &buffer, flags);
318  jobject byte_buffer = 0;
319  if (result == MOJO_RESULT_OK) {
320    byte_buffer = env->NewDirectByteBuffer(buffer, num_bytes);
321  }
322  return Java_CoreImpl_newNativeCodeAndBufferResult(env, result, byte_buffer)
323      .Release();
324}
325
326static int Unmap(JNIEnv* env, jobject jcaller, jobject buffer) {
327  void* buffer_start = env->GetDirectBufferAddress(buffer);
328  DCHECK(buffer_start);
329  return MojoUnmapBuffer(buffer_start);
330}
331
332static jobject AsyncWait(JNIEnv* env,
333                         jobject jcaller,
334                         jint mojo_handle,
335                         jint signals,
336                         jlong deadline,
337                         jobject callback) {
338  AsyncWaitCallbackData* callback_data =
339      new AsyncWaitCallbackData(env, jcaller, callback);
340  MojoAsyncWaitID cancel_id;
341  if (static_cast<MojoHandle>(mojo_handle) != MOJO_HANDLE_INVALID) {
342    cancel_id = Environment::GetDefaultAsyncWaiter()->AsyncWait(
343        mojo_handle, signals, deadline, AsyncWaitCallback, callback_data);
344  } else {
345    cancel_id = kInvalidHandleCancelID;
346    base::MessageLoop::current()->PostTask(
347        FROM_HERE,
348        base::Bind(
349            &AsyncWaitCallback, callback_data, MOJO_RESULT_INVALID_ARGUMENT));
350  }
351  base::android::ScopedJavaLocalRef<jobject> cancellable =
352      Java_CoreImpl_newAsyncWaiterCancellableImpl(
353          env, jcaller, cancel_id, reinterpret_cast<intptr_t>(callback_data));
354  callback_data->cancellable.Reset(env, cancellable.obj());
355  return cancellable.Release();
356}
357
358static void CancelAsyncWait(JNIEnv* env,
359                            jobject jcaller,
360                            jlong id,
361                            jlong data_ptr) {
362  if (id == 0) {
363    // If |id| is |kInvalidHandleCancelID|, the async wait was done on an
364    // invalid handle, so the AsyncWaitCallback will be called and will clear
365    // the data_ptr.
366    return;
367  }
368  scoped_ptr<AsyncWaitCallbackData> deleter(
369      reinterpret_cast<AsyncWaitCallbackData*>(data_ptr));
370  Environment::GetDefaultAsyncWaiter()->CancelWait(id);
371}
372
373bool RegisterCoreImpl(JNIEnv* env) {
374  return RegisterNativesImpl(env);
375}
376
377}  // namespace android
378}  // namespace mojo
379