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