1 // Copyright 2018 The Chromium Authors
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/task_runner_android.h"
6
7 #include <array>
8 #include <string>
9 #include <utility>
10
11 #include "base/android/jni_string.h"
12 #include "base/android_runtime_jni_headers/Runnable_jni.h"
13 #include "base/base_jni/TaskRunnerImpl_jni.h"
14 #include "base/check.h"
15 #include "base/compiler_specific.h"
16 #include "base/functional/bind.h"
17 #include "base/no_destructor.h"
18 #include "base/strings/strcat.h"
19 #include "base/task/current_thread.h"
20 #include "base/task/task_traits.h"
21 #include "base/task/thread_pool.h"
22 #include "base/task/thread_pool/thread_pool_impl.h"
23 #include "base/task/thread_pool/thread_pool_instance.h"
24 #include "base/time/time.h"
25 #include "base/trace_event/base_tracing.h"
26
27 namespace base {
28
29 namespace {
30
GetUiThreadTaskRunnerCallback()31 TaskRunnerAndroid::UiThreadTaskRunnerCallback& GetUiThreadTaskRunnerCallback() {
32 static base::NoDestructor<TaskRunnerAndroid::UiThreadTaskRunnerCallback>
33 callback;
34 return *callback;
35 }
36
RunJavaTask(base::android::ScopedJavaGlobalRef<jobject> task,const std::string & runnable_class_name)37 void RunJavaTask(base::android::ScopedJavaGlobalRef<jobject> task,
38 const std::string& runnable_class_name) {
39 TRACE_EVENT("toplevel", nullptr, [&](::perfetto::EventContext& ctx) {
40 std::string event_name =
41 base::StrCat({"JniPostTask: ", runnable_class_name});
42 ctx.event()->set_name(event_name.c_str());
43 });
44 JNIEnv* env = jni_zero::AttachCurrentThread();
45 JNI_Runnable::Java_Runnable_run(env, task);
46 }
47
48 } // namespace
49
JNI_TaskRunnerImpl_Init(JNIEnv * env,jint task_runner_type,jint task_traits)50 jlong JNI_TaskRunnerImpl_Init(JNIEnv* env,
51 jint task_runner_type,
52 jint task_traits) {
53 TaskRunnerAndroid* task_runner =
54 TaskRunnerAndroid::Create(task_runner_type, task_traits).release();
55 return reinterpret_cast<intptr_t>(task_runner);
56 }
57
TaskRunnerAndroid(scoped_refptr<TaskRunner> task_runner,TaskRunnerType type)58 TaskRunnerAndroid::TaskRunnerAndroid(scoped_refptr<TaskRunner> task_runner,
59 TaskRunnerType type)
60 : task_runner_(std::move(task_runner)), type_(type) {}
61
62 TaskRunnerAndroid::~TaskRunnerAndroid() = default;
63
Destroy(JNIEnv * env)64 void TaskRunnerAndroid::Destroy(JNIEnv* env) {
65 // This could happen on any thread.
66 delete this;
67 }
68
PostDelayedTask(JNIEnv * env,const base::android::JavaRef<jobject> & task,jlong delay,std::string & runnable_class_name)69 void TaskRunnerAndroid::PostDelayedTask(
70 JNIEnv* env,
71 const base::android::JavaRef<jobject>& task,
72 jlong delay,
73 std::string& runnable_class_name) {
74 // This could be run on any java thread, so we can't cache |env| in the
75 // BindOnce because JNIEnv is thread specific.
76 task_runner_->PostDelayedTask(
77 FROM_HERE,
78 base::BindOnce(&RunJavaTask,
79 base::android::ScopedJavaGlobalRef<jobject>(task),
80 runnable_class_name),
81 Milliseconds(delay));
82 }
83
BelongsToCurrentThread(JNIEnv * env)84 bool TaskRunnerAndroid::BelongsToCurrentThread(JNIEnv* env) {
85 // TODO(crbug.com/1026641): Move BelongsToCurrentThread from TaskRunnerImpl to
86 // SequencedTaskRunnerImpl on the Java side too.
87 if (type_ == TaskRunnerType::BASE)
88 return false;
89 return static_cast<SequencedTaskRunner*>(task_runner_.get())
90 ->RunsTasksInCurrentSequence();
91 }
92
93 // static
Create(jint task_runner_type,jint j_task_traits)94 std::unique_ptr<TaskRunnerAndroid> TaskRunnerAndroid::Create(
95 jint task_runner_type,
96 jint j_task_traits) {
97 TaskTraits task_traits;
98 bool use_thread_pool = true;
99 switch (j_task_traits) {
100 case ::TaskTraits::BEST_EFFORT:
101 task_traits = {TaskPriority::BEST_EFFORT};
102 break;
103 case ::TaskTraits::BEST_EFFORT_MAY_BLOCK:
104 task_traits = {base::MayBlock(), TaskPriority::BEST_EFFORT};
105 break;
106 case ::TaskTraits::USER_VISIBLE:
107 task_traits = {TaskPriority::USER_VISIBLE};
108 break;
109 case ::TaskTraits::USER_VISIBLE_MAY_BLOCK:
110 task_traits = {base::MayBlock(), TaskPriority::USER_VISIBLE};
111 break;
112 case ::TaskTraits::USER_BLOCKING:
113 task_traits = {TaskPriority::USER_BLOCKING};
114 break;
115 case ::TaskTraits::USER_BLOCKING_MAY_BLOCK:
116 task_traits = {base::MayBlock(), TaskPriority::USER_BLOCKING};
117 break;
118 case ::TaskTraits::UI_BEST_EFFORT:
119 [[fallthrough]];
120 case ::TaskTraits::UI_USER_VISIBLE:
121 [[fallthrough]];
122 case ::TaskTraits::UI_USER_BLOCKING:
123 use_thread_pool = false;
124 break;
125 }
126 scoped_refptr<TaskRunner> task_runner;
127 if (use_thread_pool) {
128 switch (static_cast<TaskRunnerType>(task_runner_type)) {
129 case TaskRunnerType::BASE:
130 task_runner = base::ThreadPool::CreateTaskRunner(task_traits);
131 break;
132 case TaskRunnerType::SEQUENCED:
133 task_runner = base::ThreadPool::CreateSequencedTaskRunner(task_traits);
134 break;
135 case TaskRunnerType::SINGLE_THREAD:
136 task_runner = base::ThreadPool::CreateSingleThreadTaskRunner(
137 task_traits, SingleThreadTaskRunnerThreadMode::SHARED);
138 break;
139 }
140 } else {
141 CHECK(static_cast<TaskRunnerType>(task_runner_type) ==
142 TaskRunnerType::SINGLE_THREAD);
143 CHECK(GetUiThreadTaskRunnerCallback());
144 task_runner = GetUiThreadTaskRunnerCallback().Run(
145 static_cast<::TaskTraits>(j_task_traits));
146 }
147 return std::make_unique<TaskRunnerAndroid>(
148 task_runner, static_cast<TaskRunnerType>(task_runner_type));
149 }
150
151 // static
SetUiThreadTaskRunnerCallback(UiThreadTaskRunnerCallback callback)152 void TaskRunnerAndroid::SetUiThreadTaskRunnerCallback(
153 UiThreadTaskRunnerCallback callback) {
154 GetUiThreadTaskRunnerCallback() = std::move(callback);
155 }
156
157 } // namespace base
158