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