task_runner_android.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. #include "base/android/task_scheduler/task_runner_android.h"
  5. #include <array>
  6. #include <string>
  7. #include <utility>
  8. #include "base/android/jni_string.h"
  9. #include "base/android_runtime_jni_headers/Runnable_jni.h"
  10. #include "base/base_jni_headers/TaskRunnerImpl_jni.h"
  11. #include "base/bind.h"
  12. #include "base/check.h"
  13. #include "base/strings/strcat.h"
  14. #include "base/task/task_executor.h"
  15. #include "base/task/thread_pool/thread_pool_impl.h"
  16. #include "base/task/thread_pool/thread_pool_instance.h"
  17. #include "base/time/time.h"
  18. #include "base/trace_event/base_tracing.h"
  19. namespace base {
  20. // As a class so it can be friend'ed.
  21. class AndroidTaskTraits {
  22. public:
  23. AndroidTaskTraits() = delete;
  24. static TaskTraits Create(
  25. JNIEnv* env,
  26. jint priority,
  27. jboolean may_block,
  28. jbyte extension_id,
  29. const base::android::JavaParamRef<jbyteArray>& extension_data) {
  30. return TaskTraits(
  31. static_cast<TaskPriority>(priority), may_block,
  32. TaskTraitsExtensionStorage(static_cast<uint8_t>(extension_id),
  33. GetExtensionData(env, extension_data)));
  34. }
  35. private:
  36. static std::array<uint8_t, TaskTraitsExtensionStorage::kStorageSize>
  37. GetExtensionData(
  38. JNIEnv* env,
  39. const base::android::JavaParamRef<jbyteArray>& array_object) {
  40. if (env->IsSameObject(array_object, nullptr))
  41. return std::array<uint8_t, TaskTraitsExtensionStorage::kStorageSize>();
  42. jbyteArray array = static_cast<jbyteArray>(array_object);
  43. DCHECK_EQ(env->GetArrayLength(array),
  44. static_cast<jsize>(TaskTraitsExtensionStorage::kStorageSize));
  45. std::array<uint8_t, TaskTraitsExtensionStorage::kStorageSize> result;
  46. jbyte* src_bytes = env->GetByteArrayElements(array, nullptr);
  47. memcpy(&result[0], src_bytes, TaskTraitsExtensionStorage::kStorageSize);
  48. env->ReleaseByteArrayElements(array, src_bytes, JNI_ABORT);
  49. return result;
  50. }
  51. };
  52. namespace {
  53. // TODO(1026641): Make destination explicit (separate APIs) on Java side too and
  54. // get rid of the need for TaskTraitsExtension/etc to reach the UI thread.
  55. TaskExecutor* GetTaskExecutor(bool use_thread_pool, const TaskTraits& traits) {
  56. const bool has_extension =
  57. traits.extension_id() != TaskTraitsExtensionStorage::kInvalidExtensionId;
  58. DCHECK(has_extension ^ use_thread_pool)
  59. << "A destination (e.g. ThreadPool or UiThreadTaskTraits) is required.";
  60. if (use_thread_pool) {
  61. DCHECK(ThreadPoolInstance::Get())
  62. << "Hint: if this is in a unit test, you're likely merely missing a "
  63. "base::test::TaskEnvironment member in your fixture (or your "
  64. "fixture is using a base::test::SingleThreadTaskEnvironment and now "
  65. "needs a full base::test::TaskEnvironment).\n";
  66. return static_cast<internal::ThreadPoolImpl*>(ThreadPoolInstance::Get());
  67. }
  68. // Assume |has_extension| per above invariant.
  69. TaskExecutor* executor = GetRegisteredTaskExecutorForTraits(traits);
  70. DCHECK(executor)
  71. << "A TaskExecutor wasn't yet registered for this extension.\n"
  72. "Hint: if this is in a unit test, you're likely missing a "
  73. "content::BrowserTaskEnvironment member in your fixture.";
  74. return executor;
  75. }
  76. void RunJavaTask(base::android::ScopedJavaGlobalRef<jobject> task,
  77. const std::string& runnable_class_name) {
  78. // JNIEnv is thread specific, but we don't know which thread we'll be run on
  79. // so we must look it up.
  80. std::string event_name = base::StrCat({"JniPostTask: ", runnable_class_name});
  81. TRACE_EVENT("toplevel", nullptr, [&](::perfetto::EventContext& ctx) {
  82. ctx.event()->set_name(event_name.c_str());
  83. });
  84. JNI_Runnable::Java_Runnable_run(base::android::AttachCurrentThread(), task);
  85. }
  86. } // namespace
  87. jlong JNI_TaskRunnerImpl_Init(
  88. JNIEnv* env,
  89. jint task_runner_type,
  90. jint priority,
  91. jboolean may_block,
  92. jboolean use_thread_pool,
  93. jbyte extension_id,
  94. const base::android::JavaParamRef<jbyteArray>& extension_data) {
  95. TaskRunnerAndroid* task_runner =
  96. TaskRunnerAndroid::Create(env, task_runner_type, priority, may_block,
  97. use_thread_pool, extension_id, extension_data)
  98. .release();
  99. return reinterpret_cast<intptr_t>(task_runner);
  100. }
  101. TaskRunnerAndroid::TaskRunnerAndroid(scoped_refptr<TaskRunner> task_runner,
  102. TaskRunnerType type)
  103. : task_runner_(std::move(task_runner)), type_(type) {}
  104. TaskRunnerAndroid::~TaskRunnerAndroid() = default;
  105. void TaskRunnerAndroid::Destroy(JNIEnv* env) {
  106. // This could happen on any thread.
  107. delete this;
  108. }
  109. void TaskRunnerAndroid::PostDelayedTask(
  110. JNIEnv* env,
  111. const base::android::JavaRef<jobject>& task,
  112. jlong delay,
  113. jstring runnable_class_name) {
  114. // This could be run on any java thread, so we can't cache |env| in the
  115. // BindOnce because JNIEnv is thread specific.
  116. task_runner_->PostDelayedTask(
  117. FROM_HERE,
  118. base::BindOnce(
  119. &RunJavaTask, base::android::ScopedJavaGlobalRef<jobject>(task),
  120. android::ConvertJavaStringToUTF8(env, runnable_class_name)),
  121. Milliseconds(delay));
  122. }
  123. bool TaskRunnerAndroid::BelongsToCurrentThread(JNIEnv* env) {
  124. // TODO(crbug.com/1026641): Move BelongsToCurrentThread from TaskRunnerImpl to
  125. // SequencedTaskRunnerImpl on the Java side too.
  126. if (type_ == TaskRunnerType::BASE)
  127. return false;
  128. return static_cast<SequencedTaskRunner*>(task_runner_.get())
  129. ->RunsTasksInCurrentSequence();
  130. }
  131. // static
  132. std::unique_ptr<TaskRunnerAndroid> TaskRunnerAndroid::Create(
  133. JNIEnv* env,
  134. jint task_runner_type,
  135. jint priority,
  136. jboolean may_block,
  137. jboolean use_thread_pool,
  138. jbyte extension_id,
  139. const base::android::JavaParamRef<jbyteArray>& extension_data) {
  140. const TaskTraits task_traits = AndroidTaskTraits::Create(
  141. env, priority, may_block, extension_id, extension_data);
  142. TaskExecutor* const task_executor =
  143. GetTaskExecutor(use_thread_pool, task_traits);
  144. scoped_refptr<TaskRunner> task_runner;
  145. switch (static_cast<TaskRunnerType>(task_runner_type)) {
  146. case TaskRunnerType::BASE:
  147. task_runner = task_executor->CreateTaskRunner(task_traits);
  148. break;
  149. case TaskRunnerType::SEQUENCED:
  150. task_runner = task_executor->CreateSequencedTaskRunner(task_traits);
  151. break;
  152. case TaskRunnerType::SINGLE_THREAD:
  153. task_runner = task_executor->CreateSingleThreadTaskRunner(
  154. task_traits, SingleThreadTaskRunnerThreadMode::SHARED);
  155. break;
  156. }
  157. return std::make_unique<TaskRunnerAndroid>(
  158. task_runner, static_cast<TaskRunnerType>(task_runner_type));
  159. }
  160. } // namespace base