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