Flutter Engine
The Flutter Engine
android_shell_holder.cc
Go to the documentation of this file.
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#include <memory>
13#include <optional>
14
15#include <sstream>
16#include <string>
17#include <utility>
18
19#include "flutter/fml/cpu_affinity.h"
20#include "flutter/fml/logging.h"
21#include "flutter/fml/make_copyable.h"
22#include "flutter/fml/message_loop.h"
23#include "flutter/fml/native_library.h"
24#include "flutter/fml/platform/android/jni_util.h"
25#include "flutter/lib/ui/painting/image_generator_registry.h"
26#include "flutter/shell/common/rasterizer.h"
27#include "flutter/shell/common/run_configuration.h"
28#include "flutter/shell/common/thread_host.h"
29#include "flutter/shell/platform/android/android_display.h"
30#include "flutter/shell/platform/android/android_image_generator.h"
31#include "flutter/shell/platform/android/context/android_context.h"
32#include "flutter/shell/platform/android/platform_view_android.h"
33
34namespace flutter {
35
36/// Inheriting ThreadConfigurer and use Android platform thread API to configure
37/// the thread priorities
39 const fml::Thread::ThreadConfig& config) {
40 // set thread name
42 // set thread priority
43 switch (config.priority) {
46 if (::setpriority(PRIO_PROCESS, 0, 10) != 0) {
47 FML_LOG(ERROR) << "Failed to set IO task runner priority";
48 }
49 break;
50 }
53 if (::setpriority(PRIO_PROCESS, 0, -1) != 0) {
54 FML_LOG(ERROR) << "Failed to set UI task runner priority";
55 }
56 break;
57 }
60 // Android describes -8 as "most important display threads, for
61 // compositing the screen and retrieving input events". Conservatively
62 // set the raster thread to slightly lower priority than it.
63 if (::setpriority(PRIO_PROCESS, 0, -5) != 0) {
64 // Defensive fallback. Depending on the OEM, it may not be possible
65 // to set priority to -5.
66 if (::setpriority(PRIO_PROCESS, 0, -2) != 0) {
67 FML_LOG(ERROR) << "Failed to set raster task runner priority";
68 }
69 }
70 break;
71 }
72 default:
74 if (::setpriority(PRIO_PROCESS, 0, 0) != 0) {
75 FML_LOG(ERROR) << "Failed to set priority";
76 }
77 }
78}
80 PlatformData platform_data;
81 platform_data.lifecycle_state = "AppLifecycleState.detached";
82 return platform_data;
83}
84
87 std::shared_ptr<PlatformViewAndroidJNI> jni_facade)
88 : settings_(settings), jni_facade_(jni_facade) {
89 static size_t thread_host_count = 1;
90 auto thread_label = std::to_string(thread_host_count++);
91
92 auto mask =
93 ThreadHost::Type::kUi | ThreadHost::Type::kRaster | ThreadHost::Type::kIo;
94
96 thread_label, mask, AndroidPlatformThreadConfigSetter);
99 flutter::ThreadHost::Type::kUi, thread_label),
107 flutter::ThreadHost::Type::kIo, thread_label),
109
110 thread_host_ = std::make_shared<ThreadHost>(host_config);
111
112 fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
113 Shell::CreateCallback<PlatformView> on_create_platform_view =
114 [&jni_facade, &weak_platform_view](Shell& shell) {
115 std::unique_ptr<PlatformViewAndroid> platform_view_android;
116 platform_view_android = std::make_unique<PlatformViewAndroid>(
117 shell, // delegate
118 shell.GetTaskRunners(), // task runners
119 jni_facade, // JNI interop
120 shell.GetSettings()
121 .enable_software_rendering // use software rendering
122 );
123 weak_platform_view = platform_view_android->GetWeakPtr();
124 return platform_view_android;
125 };
126
127 Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
128 return std::make_unique<Rasterizer>(shell);
129 };
130
131 // The current thread will be used as the platform thread. Ensure that the
132 // message loop is initialized.
134 fml::RefPtr<fml::TaskRunner> raster_runner;
137 fml::RefPtr<fml::TaskRunner> platform_runner =
139 raster_runner = thread_host_->raster_thread->GetTaskRunner();
140 ui_runner = thread_host_->ui_thread->GetTaskRunner();
141 io_runner = thread_host_->io_thread->GetTaskRunner();
142
143 flutter::TaskRunners task_runners(thread_label, // label
144 platform_runner, // platform
145 raster_runner, // raster
146 ui_runner, // ui
147 io_runner // io
148 );
149
150 shell_ =
151 Shell::Create(GetDefaultPlatformData(), // window data
152 task_runners, // task runners
153 settings_, // settings
154 on_create_platform_view, // platform view create callback
155 on_create_rasterizer // rasterizer create callback
156 );
157
158 if (shell_) {
159 shell_->GetDartVM()->GetConcurrentMessageLoop()->PostTaskToAllWorkers([]() {
160 if (::setpriority(PRIO_PROCESS, gettid(), 1) != 0) {
161 FML_LOG(ERROR) << "Failed to set Workers task runner priority";
162 }
163 });
164
165 shell_->RegisterImageDecoder(
166 [runner = task_runners.GetIOTaskRunner()](sk_sp<SkData> buffer) {
167 return AndroidImageGenerator::MakeFromData(std::move(buffer), runner);
168 },
169 -1);
170 FML_DLOG(INFO) << "Registered Android SDK image decoder (API level 28+)";
171 }
172
173 platform_view_ = weak_platform_view;
174 FML_DCHECK(platform_view_);
175 is_valid_ = shell_ != nullptr;
176}
177
179 const Settings& settings,
180 const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade,
181 const std::shared_ptr<ThreadHost>& thread_host,
182 std::unique_ptr<Shell> shell,
183 std::unique_ptr<APKAssetProvider> apk_asset_provider,
186 jni_facade_(jni_facade),
187 platform_view_(platform_view),
188 thread_host_(thread_host),
189 shell_(std::move(shell)),
190 apk_asset_provider_(std::move(apk_asset_provider)) {
191 FML_DCHECK(jni_facade);
192 FML_DCHECK(shell_);
193 FML_DCHECK(shell_->IsSetup());
194 FML_DCHECK(platform_view_);
195 FML_DCHECK(thread_host_);
196 is_valid_ = shell_ != nullptr;
197}
198
200 shell_.reset();
201 thread_host_.reset();
202}
203
205 return is_valid_;
206}
207
209 return settings_;
210}
211
212std::unique_ptr<AndroidShellHolder> AndroidShellHolder::Spawn(
213 std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
214 const std::string& entrypoint,
215 const std::string& libraryUrl,
216 const std::string& initial_route,
217 const std::vector<std::string>& entrypoint_args) const {
218 FML_DCHECK(shell_ && shell_->IsSetup())
219 << "A new Shell can only be spawned "
220 "if the current Shell is properly constructed";
221
222 // Pull out the new PlatformViewAndroid from the new Shell to feed to it to
223 // the new AndroidShellHolder.
224 //
225 // It's a weak pointer because it's owned by the Shell (which we're also)
226 // making below. And the AndroidShellHolder then owns the Shell.
227 fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
228
229 // Take out the old AndroidContext to reuse inside the PlatformViewAndroid
230 // of the new Shell.
231 PlatformViewAndroid* android_platform_view = platform_view_.get();
232 // There's some indirection with platform_view_ being a weak pointer but
233 // we just checked that the shell_ exists above and a valid shell is the
234 // owner of the platform view so this weak pointer always exists.
235 FML_DCHECK(android_platform_view);
236 std::shared_ptr<flutter::AndroidContext> android_context =
237 android_platform_view->GetAndroidContext();
238 FML_DCHECK(android_context);
239
240 // This is a synchronous call, so the captures don't have race checks.
241 Shell::CreateCallback<PlatformView> on_create_platform_view =
242 [&jni_facade, android_context, &weak_platform_view](Shell& shell) {
243 std::unique_ptr<PlatformViewAndroid> platform_view_android;
244 platform_view_android = std::make_unique<PlatformViewAndroid>(
245 shell, // delegate
246 shell.GetTaskRunners(), // task runners
247 jni_facade, // JNI interop
248 android_context // Android context
249 );
250 weak_platform_view = platform_view_android->GetWeakPtr();
251 return platform_view_android;
252 };
253
254 Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
255 return std::make_unique<Rasterizer>(shell);
256 };
257
258 // TODO(xster): could be worth tracing this to investigate whether
259 // the IsolateConfiguration could be cached somewhere.
260 auto config = BuildRunConfiguration(entrypoint, libraryUrl, entrypoint_args);
261 if (!config) {
262 // If the RunConfiguration was null, the kernel blob wasn't readable.
263 // Fail the whole thing.
264 return nullptr;
265 }
266
267 std::unique_ptr<flutter::Shell> shell =
268 shell_->Spawn(std::move(config.value()), initial_route,
269 on_create_platform_view, on_create_rasterizer);
270
271 return std::unique_ptr<AndroidShellHolder>(new AndroidShellHolder(
272 GetSettings(), jni_facade, thread_host_, std::move(shell),
273 apk_asset_provider_->Clone(), weak_platform_view));
274}
275
277 std::unique_ptr<APKAssetProvider> apk_asset_provider,
278 const std::string& entrypoint,
279 const std::string& libraryUrl,
280 const std::vector<std::string>& entrypoint_args) {
281 if (!IsValid()) {
282 return;
283 }
284
285 apk_asset_provider_ = std::move(apk_asset_provider);
286 auto config = BuildRunConfiguration(entrypoint, libraryUrl, entrypoint_args);
287 if (!config) {
288 return;
289 }
291 shell_->RunEngine(std::move(config.value()));
292}
293
296 bool base64_encode) {
297 if (!IsValid()) {
298 return {nullptr, SkISize::MakeEmpty(), "",
300 }
301 return shell_->Screenshot(type, base64_encode);
302}
303
305 FML_DCHECK(platform_view_);
306 return platform_view_;
307}
308
310 FML_DCHECK(shell_);
311 shell_->NotifyLowMemoryWarning();
312}
313
314std::optional<RunConfiguration> AndroidShellHolder::BuildRunConfiguration(
315 const std::string& entrypoint,
316 const std::string& libraryUrl,
317 const std::vector<std::string>& entrypoint_args) const {
318 std::unique_ptr<IsolateConfiguration> isolate_configuration;
320 isolate_configuration = IsolateConfiguration::CreateForAppSnapshot();
321 } else {
322 std::unique_ptr<fml::Mapping> kernel_blob =
324 GetSettings().application_kernel_asset);
325 if (!kernel_blob) {
326 FML_DLOG(ERROR) << "Unable to load the kernel blob asset.";
327 return std::nullopt;
328 }
329 isolate_configuration =
330 IsolateConfiguration::CreateForKernel(std::move(kernel_blob));
331 }
332
333 RunConfiguration config(std::move(isolate_configuration));
334 config.AddAssetResolver(apk_asset_provider_->Clone());
335
336 {
337 if (!entrypoint.empty() && !libraryUrl.empty()) {
338 config.SetEntrypointAndLibrary(entrypoint, libraryUrl);
339 } else if (!entrypoint.empty()) {
340 config.SetEntrypoint(entrypoint);
341 }
342 if (!entrypoint_args.empty()) {
343 config.SetEntrypointArgs(entrypoint_args);
344 }
345 }
346 return config;
347}
348
350 std::vector<std::unique_ptr<Display>> displays;
351 displays.push_back(std::make_unique<AndroidDisplay>(jni_facade_));
352 shell_->OnDisplayUpdates(std::move(displays));
353}
354
355} // namespace flutter
std::unique_ptr< flutter::PlatformViewIOS > platform_view
GLenum type
static std::shared_ptr< ImageGenerator > MakeFromData(sk_sp< SkData > data, const fml::RefPtr< fml::TaskRunner > &task_runner)
const flutter::Settings & GetSettings() const
std::unique_ptr< AndroidShellHolder > Spawn(std::shared_ptr< PlatformViewAndroidJNI > jni_facade, const std::string &entrypoint, const std::string &libraryUrl, const std::string &initial_route, const std::vector< std::string > &entrypoint_args) const
This is a factory for a derived AndroidShellHolder from an existing AndroidShellHolder.
fml::WeakPtr< PlatformViewAndroid > GetPlatformView()
Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, bool base64_encode)
void Launch(std::unique_ptr< APKAssetProvider > apk_asset_provider, const std::string &entrypoint, const std::string &libraryUrl, const std::vector< std::string > &entrypoint_args)
AndroidShellHolder(const flutter::Settings &settings, std::shared_ptr< PlatformViewAndroidJNI > jni_facade)
static bool IsRunningPrecompiledCode()
Checks if VM instances in the process can run precompiled code. This call can be made at any time and...
Definition: dart_vm.cc:205
static std::unique_ptr< IsolateConfiguration > CreateForAppSnapshot()
Creates an AOT isolate configuration using snapshot symbols present in the currently loaded process....
static std::unique_ptr< IsolateConfiguration > CreateForKernel(std::unique_ptr< const fml::Mapping > kernel)
Creates a JIT isolate configuration using the specified snapshot. This is a convenience method for th...
const std::shared_ptr< AndroidContext > & GetAndroidContext()
ScreenshotType
The type of the screenshot to obtain of the previously rendered layer tree.
Definition: rasterizer.h:347
static std::unique_ptr< Shell > Create(const PlatformData &platform_data, const TaskRunners &task_runners, Settings settings, const CreateCallback< PlatformView > &on_create_platform_view, const CreateCallback< Rasterizer > &on_create_rasterizer, bool is_gpu_disabled=false)
Creates a shell instance using the provided settings. The callbacks to create the various shell subco...
Definition: shell.cc:169
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition: shell.h:120
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
Definition: task_runners.cc:38
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
Definition: mapping.cc:20
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
@ kNormal
Default priority level.
@ kRaster
Suitable for thread which raster data.
@ kBackground
Suitable for threads that shouldn't disrupt high priority work.
@ kDisplay
Suitable for threads which generate data for the display.
static void SetCurrentThreadName(const ThreadConfig &config)
Definition: thread.cc:135
@ kRaster
Suitable for thread which raster data.
Definition: embedder.h:266
Settings settings_
ThreadHost thread_host_
#define FML_DLOG(severity)
Definition: logging.h:102
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_DCHECK(condition)
Definition: logging.h:103
static PlatformData GetDefaultPlatformData()
fml::Thread::ThreadConfig ThreadConfig
Definition: thread_host.h:17
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
static void AndroidPlatformThreadConfigSetter(const fml::Thread::ThreadConfig &config)
@ kPerformance
Request CPU affinity for the performance cores.
@ kEfficiency
Request CPU affinity for the efficiency cores.
@ kNotPerformance
Request affinity for all non-performance cores.
bool RequestAffinity(CpuAffinity affinity)
Request the given affinity for the current thread.
Definition: cpu_affinity.cc:26
Definition: ref_ptr.h:256
static SkString to_string(int n)
Definition: nanobench.cpp:119
static constexpr SkISize MakeEmpty()
Definition: SkSize.h:22
std::string lifecycle_state
Definition: platform_data.h:44
A POD type used to return the screenshot data along with the size of the frame.
Definition: rasterizer.h:398
std::optional< ThreadConfig > io_config
Definition: thread_host.h:78
std::optional< ThreadConfig > ui_config
Definition: thread_host.h:76
std::optional< ThreadConfig > raster_config
Definition: thread_host.h:77
static std::string MakeThreadName(Type type, const std::string &prefix)
Use the prefix and thread type to generator a thread name.
Definition: thread_host.cc:15
The ThreadConfig is the thread info include thread name, thread priority.
Definition: thread.h:35
ThreadPriority priority
Definition: thread.h:45
#define ERROR(message)
Definition: elf_loader.cc:260