// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #define FML_USED_ON_EMBEDDER #include "flutter/shell/platform/android/android_shell_holder.h" #include #include #include #include #include #include #include "flutter/fml/make_copyable.h" #include "flutter/fml/message_loop.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/platform/android/platform_view_android.h" namespace flutter { AndroidShellHolder::AndroidShellHolder( flutter::Settings settings, fml::jni::JavaObjectWeakGlobalRef java_object, bool is_background_view) : settings_(std::move(settings)), java_object_(java_object) { static size_t shell_count = 1; auto thread_label = std::to_string(shell_count++); FML_CHECK(pthread_key_create(&thread_destruct_key_, ThreadDestructCallback) == 0); if (is_background_view) { thread_host_ = {thread_label, ThreadHost::Type::UI}; } else { thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | ThreadHost::Type::IO}; } // Detach from JNI when the UI and GPU threads exit. auto jni_exit_task([key = thread_destruct_key_]() { FML_CHECK(pthread_setspecific(key, reinterpret_cast(1)) == 0); }); thread_host_.ui_thread->GetTaskRunner()->PostTask(jni_exit_task); if (!is_background_view) { thread_host_.gpu_thread->GetTaskRunner()->PostTask(jni_exit_task); } fml::WeakPtr weak_platform_view; Shell::CreateCallback on_create_platform_view = [is_background_view, java_object, &weak_platform_view](Shell& shell) { std::unique_ptr platform_view_android; if (is_background_view) { platform_view_android = std::make_unique( shell, // delegate shell.GetTaskRunners(), // task runners java_object // java object handle for JNI interop ); } else { platform_view_android = std::make_unique( shell, // delegate shell.GetTaskRunners(), // task runners java_object, // java object handle for JNI interop shell.GetSettings() .enable_software_rendering // use software rendering ); } weak_platform_view = platform_view_android->GetWeakPtr(); return platform_view_android; }; Shell::CreateCallback on_create_rasterizer = [](Shell& shell) { return std::make_unique(shell, shell.GetTaskRunners()); }; // The current thread will be used as the platform thread. Ensure that the // message loop is initialized. fml::MessageLoop::EnsureInitializedForCurrentThread(); fml::RefPtr gpu_runner; fml::RefPtr ui_runner; fml::RefPtr io_runner; fml::RefPtr platform_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); if (is_background_view) { auto single_task_runner = thread_host_.ui_thread->GetTaskRunner(); gpu_runner = single_task_runner; ui_runner = single_task_runner; io_runner = single_task_runner; } else { gpu_runner = thread_host_.gpu_thread->GetTaskRunner(); ui_runner = thread_host_.ui_thread->GetTaskRunner(); io_runner = thread_host_.io_thread->GetTaskRunner(); } flutter::TaskRunners task_runners(thread_label, // label platform_runner, // platform gpu_runner, // gpu ui_runner, // ui io_runner // io ); shell_ = Shell::Create(task_runners, // task runners settings_, // settings on_create_platform_view, // platform view create callback on_create_rasterizer // rasterizer create callback ); platform_view_ = weak_platform_view; FML_DCHECK(platform_view_); is_valid_ = shell_ != nullptr; if (is_valid_) { task_runners.GetGPUTaskRunner()->PostTask([]() { // Android describes -8 as "most important display threads, for // compositing the screen and retrieving input events". Conservatively // set the GPU thread to slightly lower priority than it. if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) { // Defensive fallback. Depending on the OEM, it may not be possible // to set priority to -5. if (::setpriority(PRIO_PROCESS, gettid(), -2) != 0) { FML_LOG(ERROR) << "Failed to set GPU task runner priority"; } } }); task_runners.GetUITaskRunner()->PostTask([]() { if (::setpriority(PRIO_PROCESS, gettid(), -1) != 0) { FML_LOG(ERROR) << "Failed to set UI task runner priority"; } }); } } AndroidShellHolder::~AndroidShellHolder() { shell_.reset(); thread_host_.Reset(); FML_CHECK(pthread_key_delete(thread_destruct_key_) == 0); } void AndroidShellHolder::ThreadDestructCallback(void* value) { fml::jni::DetachFromVM(); } bool AndroidShellHolder::IsValid() const { return is_valid_; } const flutter::Settings& AndroidShellHolder::GetSettings() const { return settings_; } void AndroidShellHolder::Launch(RunConfiguration config) { if (!IsValid()) { return; } shell_->RunEngine(std::move(config)); } Rasterizer::Screenshot AndroidShellHolder::Screenshot( Rasterizer::ScreenshotType type, bool base64_encode) { if (!IsValid()) { return {nullptr, SkISize::MakeEmpty()}; } return shell_->Screenshot(type, base64_encode); } fml::WeakPtr AndroidShellHolder::GetPlatformView() { FML_DCHECK(platform_view_); return platform_view_; } } // namespace flutter