1 // Copyright 2013 The Flutter 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 #define FML_USED_ON_EMBEDDER
6
7 #include "flutter/shell/platform/android/android_shell_holder.h"
8
9 #include <pthread.h>
10 #include <sys/resource.h>
11 #include <sys/time.h>
12
13 #include <sstream>
14 #include <string>
15 #include <utility>
16
17 #include "flutter/fml/make_copyable.h"
18 #include "flutter/fml/message_loop.h"
19 #include "flutter/shell/common/rasterizer.h"
20 #include "flutter/shell/platform/android/platform_view_android.h"
21
22 namespace flutter {
23
AndroidShellHolder(flutter::Settings settings,fml::jni::JavaObjectWeakGlobalRef java_object,bool is_background_view)24 AndroidShellHolder::AndroidShellHolder(
25 flutter::Settings settings,
26 fml::jni::JavaObjectWeakGlobalRef java_object,
27 bool is_background_view)
28 : settings_(std::move(settings)), java_object_(java_object) {
29 static size_t shell_count = 1;
30 auto thread_label = std::to_string(shell_count++);
31
32 FML_CHECK(pthread_key_create(&thread_destruct_key_, ThreadDestructCallback) ==
33 0);
34
35 if (is_background_view) {
36 thread_host_ = {thread_label, ThreadHost::Type::UI};
37 } else {
38 thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU |
39 ThreadHost::Type::IO};
40 }
41
42 // Detach from JNI when the UI and GPU threads exit.
43 auto jni_exit_task([key = thread_destruct_key_]() {
44 FML_CHECK(pthread_setspecific(key, reinterpret_cast<void*>(1)) == 0);
45 });
46 thread_host_.ui_thread->GetTaskRunner()->PostTask(jni_exit_task);
47 if (!is_background_view) {
48 thread_host_.gpu_thread->GetTaskRunner()->PostTask(jni_exit_task);
49 }
50
51 fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
52 Shell::CreateCallback<PlatformView> on_create_platform_view =
53 [is_background_view, java_object, &weak_platform_view](Shell& shell) {
54 std::unique_ptr<PlatformViewAndroid> platform_view_android;
55 if (is_background_view) {
56 platform_view_android = std::make_unique<PlatformViewAndroid>(
57 shell, // delegate
58 shell.GetTaskRunners(), // task runners
59 java_object // java object handle for JNI interop
60 );
61
62 } else {
63 platform_view_android = std::make_unique<PlatformViewAndroid>(
64 shell, // delegate
65 shell.GetTaskRunners(), // task runners
66 java_object, // java object handle for JNI interop
67 shell.GetSettings()
68 .enable_software_rendering // use software rendering
69 );
70 }
71 weak_platform_view = platform_view_android->GetWeakPtr();
72 return platform_view_android;
73 };
74
75 Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
76 return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
77 };
78
79 // The current thread will be used as the platform thread. Ensure that the
80 // message loop is initialized.
81 fml::MessageLoop::EnsureInitializedForCurrentThread();
82 fml::RefPtr<fml::TaskRunner> gpu_runner;
83 fml::RefPtr<fml::TaskRunner> ui_runner;
84 fml::RefPtr<fml::TaskRunner> io_runner;
85 fml::RefPtr<fml::TaskRunner> platform_runner =
86 fml::MessageLoop::GetCurrent().GetTaskRunner();
87 if (is_background_view) {
88 auto single_task_runner = thread_host_.ui_thread->GetTaskRunner();
89 gpu_runner = single_task_runner;
90 ui_runner = single_task_runner;
91 io_runner = single_task_runner;
92 } else {
93 gpu_runner = thread_host_.gpu_thread->GetTaskRunner();
94 ui_runner = thread_host_.ui_thread->GetTaskRunner();
95 io_runner = thread_host_.io_thread->GetTaskRunner();
96 }
97 flutter::TaskRunners task_runners(thread_label, // label
98 platform_runner, // platform
99 gpu_runner, // gpu
100 ui_runner, // ui
101 io_runner // io
102 );
103
104 shell_ =
105 Shell::Create(task_runners, // task runners
106 settings_, // settings
107 on_create_platform_view, // platform view create callback
108 on_create_rasterizer // rasterizer create callback
109 );
110
111 platform_view_ = weak_platform_view;
112 FML_DCHECK(platform_view_);
113
114 is_valid_ = shell_ != nullptr;
115
116 if (is_valid_) {
117 task_runners.GetGPUTaskRunner()->PostTask([]() {
118 // Android describes -8 as "most important display threads, for
119 // compositing the screen and retrieving input events". Conservatively
120 // set the GPU thread to slightly lower priority than it.
121 if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) {
122 // Defensive fallback. Depending on the OEM, it may not be possible
123 // to set priority to -5.
124 if (::setpriority(PRIO_PROCESS, gettid(), -2) != 0) {
125 FML_LOG(ERROR) << "Failed to set GPU task runner priority";
126 }
127 }
128 });
129 task_runners.GetUITaskRunner()->PostTask([]() {
130 if (::setpriority(PRIO_PROCESS, gettid(), -1) != 0) {
131 FML_LOG(ERROR) << "Failed to set UI task runner priority";
132 }
133 });
134 }
135 }
136
~AndroidShellHolder()137 AndroidShellHolder::~AndroidShellHolder() {
138 shell_.reset();
139 thread_host_.Reset();
140 FML_CHECK(pthread_key_delete(thread_destruct_key_) == 0);
141 }
142
ThreadDestructCallback(void * value)143 void AndroidShellHolder::ThreadDestructCallback(void* value) {
144 fml::jni::DetachFromVM();
145 }
146
IsValid() const147 bool AndroidShellHolder::IsValid() const {
148 return is_valid_;
149 }
150
GetSettings() const151 const flutter::Settings& AndroidShellHolder::GetSettings() const {
152 return settings_;
153 }
154
Launch(RunConfiguration config)155 void AndroidShellHolder::Launch(RunConfiguration config) {
156 if (!IsValid()) {
157 return;
158 }
159
160 shell_->RunEngine(std::move(config));
161 }
162
Screenshot(Rasterizer::ScreenshotType type,bool base64_encode)163 Rasterizer::Screenshot AndroidShellHolder::Screenshot(
164 Rasterizer::ScreenshotType type,
165 bool base64_encode) {
166 if (!IsValid()) {
167 return {nullptr, SkISize::MakeEmpty()};
168 }
169 return shell_->Screenshot(type, base64_encode);
170 }
171
GetPlatformView()172 fml::WeakPtr<PlatformViewAndroid> AndroidShellHolder::GetPlatformView() {
173 FML_DCHECK(platform_view_);
174 return platform_view_;
175 }
176
177 } // namespace flutter
178