1 // Copyright 2018 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 "base/android/task_scheduler/post_task_android.h"
6 
7 #include "base/android_runtime_jni_headers/Runnable_jni.h"
8 #include "base/base_jni_headers/PostTask_jni.h"
9 #include "base/no_destructor.h"
10 #include "base/run_loop.h"
11 #include "base/task/post_task.h"
12 #include "base/task/thread_pool/thread_pool_instance.h"
13 
14 namespace base {
15 
16 // static
SignalNativeSchedulerReady()17 void PostTaskAndroid::SignalNativeSchedulerReady() {
18   Java_PostTask_onNativeSchedulerReady(base::android::AttachCurrentThread());
19 }
20 
21 // static
SignalNativeSchedulerShutdownForTesting()22 void PostTaskAndroid::SignalNativeSchedulerShutdownForTesting() {
23   Java_PostTask_onNativeSchedulerShutdownForTesting(
24       base::android::AttachCurrentThread());
25 }
26 
27 namespace {
GetExtensionData(JNIEnv * env,const base::android::JavaParamRef<jbyteArray> & array_object)28 std::array<uint8_t, TaskTraitsExtensionStorage::kStorageSize> GetExtensionData(
29     JNIEnv* env,
30     const base::android::JavaParamRef<jbyteArray>& array_object) {
31   if (env->IsSameObject(array_object, nullptr))
32     return std::array<uint8_t, TaskTraitsExtensionStorage::kStorageSize>();
33 
34   jbyteArray array = static_cast<jbyteArray>(array_object);
35   DCHECK_EQ(env->GetArrayLength(array),
36             static_cast<jsize>(TaskTraitsExtensionStorage::kStorageSize));
37 
38   std::array<uint8_t, TaskTraitsExtensionStorage::kStorageSize> result;
39   jbyte* src_bytes = env->GetByteArrayElements(array, nullptr);
40   memcpy(&result[0], src_bytes, TaskTraitsExtensionStorage::kStorageSize);
41   env->ReleaseByteArrayElements(array, src_bytes, JNI_ABORT);
42   return result;
43 }
44 }  // namespace
45 
46 // static
CreateTaskTraits(JNIEnv * env,jint priority,jboolean may_block,jboolean use_thread_pool,jbyte extension_id,const base::android::JavaParamRef<jbyteArray> & extension_data)47 TaskTraits PostTaskAndroid::CreateTaskTraits(
48     JNIEnv* env,
49     jint priority,
50     jboolean may_block,
51     jboolean use_thread_pool,
52     jbyte extension_id,
53     const base::android::JavaParamRef<jbyteArray>& extension_data) {
54   return TaskTraits(static_cast<TaskPriority>(priority), may_block,
55                     use_thread_pool,
56                     TaskTraitsExtensionStorage(
57                         extension_id, GetExtensionData(env, extension_data)));
58 }
59 
JNI_PostTask_PostDelayedTask(JNIEnv * env,jint priority,jboolean may_block,jboolean use_thread_pool,jbyte extension_id,const base::android::JavaParamRef<jbyteArray> & extension_data,const base::android::JavaParamRef<jobject> & task,jlong delay)60 void JNI_PostTask_PostDelayedTask(
61     JNIEnv* env,
62     jint priority,
63     jboolean may_block,
64     jboolean use_thread_pool,
65     jbyte extension_id,
66     const base::android::JavaParamRef<jbyteArray>& extension_data,
67     const base::android::JavaParamRef<jobject>& task,
68     jlong delay) {
69   // This could be run on any java thread, so we can't cache |env| in the
70   // BindOnce because JNIEnv is thread specific.
71   PostDelayedTask(FROM_HERE,
72                   PostTaskAndroid::CreateTaskTraits(
73                       env, priority, may_block, use_thread_pool, extension_id,
74                       extension_data),
75                   BindOnce(&PostTaskAndroid::RunJavaTask,
76                            base::android::ScopedJavaGlobalRef<jobject>(task)),
77                   TimeDelta::FromMilliseconds(delay));
78 }
79 
80 // static
RunJavaTask(base::android::ScopedJavaGlobalRef<jobject> task)81 void PostTaskAndroid::RunJavaTask(
82     base::android::ScopedJavaGlobalRef<jobject> task) {
83   // JNIEnv is thread specific, but we don't know which thread we'll be run on
84   // so we must look it up.
85   JNI_Runnable::Java_Runnable_run(base::android::AttachCurrentThread(), task);
86 }
87 
88 }  // namespace base
89