Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
86 const flutter::Settings& settings,
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 =
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 shell.GetSettings().msaa_samples // msaa sample count
123 );
124 weak_platform_view = platform_view_android->GetWeakPtr();
125 return platform_view_android;
126 };
127
128 Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
129 return std::make_unique<Rasterizer>(shell);
130 };
131
132 // The current thread will be used as the platform thread. Ensure that the
133 // message loop is initialized.
135 fml::RefPtr<fml::TaskRunner> raster_runner;
138 fml::RefPtr<fml::TaskRunner> platform_runner =
140 raster_runner = thread_host_->raster_thread->GetTaskRunner();
141 ui_runner = thread_host_->ui_thread->GetTaskRunner();
142 io_runner = thread_host_->io_thread->GetTaskRunner();
143
144 flutter::TaskRunners task_runners(thread_label, // label
145 platform_runner, // platform
146 raster_runner, // raster
147 ui_runner, // ui
148 io_runner // io
149 );
150
151 shell_ =
152 Shell::Create(GetDefaultPlatformData(), // window data
153 task_runners, // task runners
154 settings_, // settings
155 on_create_platform_view, // platform view create callback
156 on_create_rasterizer // rasterizer create callback
157 );
158
159 if (shell_) {
160 shell_->GetDartVM()->GetConcurrentMessageLoop()->PostTaskToAllWorkers([]() {
161 if (::setpriority(PRIO_PROCESS, gettid(), 1) != 0) {
162 FML_LOG(ERROR) << "Failed to set Workers task runner priority";
163 }
164 });
165
166 shell_->RegisterImageDecoder(
167 [runner = task_runners.GetIOTaskRunner()](sk_sp<SkData> buffer) {
168 return AndroidImageGenerator::MakeFromData(std::move(buffer), runner);
169 },
170 -1);
171 FML_DLOG(INFO) << "Registered Android SDK image decoder (API level 28+)";
172 }
173
174 platform_view_ = weak_platform_view;
175 FML_DCHECK(platform_view_);
176 is_valid_ = shell_ != nullptr;
177}
178
180 const Settings& settings,
181 const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade,
182 const std::shared_ptr<ThreadHost>& thread_host,
183 std::unique_ptr<Shell> shell,
184 std::unique_ptr<APKAssetProvider> apk_asset_provider,
186 : settings_(settings),
187 jni_facade_(jni_facade),
188 platform_view_(platform_view),
189 thread_host_(thread_host),
190 shell_(std::move(shell)),
191 apk_asset_provider_(std::move(apk_asset_provider)) {
192 FML_DCHECK(jni_facade);
193 FML_DCHECK(shell_);
194 FML_DCHECK(shell_->IsSetup());
195 FML_DCHECK(platform_view_);
196 FML_DCHECK(thread_host_);
197 is_valid_ = shell_ != nullptr;
198}
199
201 shell_.reset();
202 thread_host_.reset();
203}
204
206 return is_valid_;
207}
208
210 return settings_;
211}
212
213std::unique_ptr<AndroidShellHolder> AndroidShellHolder::Spawn(
214 std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
215 const std::string& entrypoint,
216 const std::string& libraryUrl,
217 const std::string& initial_route,
218 const std::vector<std::string>& entrypoint_args) const {
219 FML_DCHECK(shell_ && shell_->IsSetup())
220 << "A new Shell can only be spawned "
221 "if the current Shell is properly constructed";
222
223 // Pull out the new PlatformViewAndroid from the new Shell to feed to it to
224 // the new AndroidShellHolder.
225 //
226 // It's a weak pointer because it's owned by the Shell (which we're also)
227 // making below. And the AndroidShellHolder then owns the Shell.
228 fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
229
230 // Take out the old AndroidContext to reuse inside the PlatformViewAndroid
231 // of the new Shell.
232 PlatformViewAndroid* android_platform_view = platform_view_.get();
233 // There's some indirection with platform_view_ being a weak pointer but
234 // we just checked that the shell_ exists above and a valid shell is the
235 // owner of the platform view so this weak pointer always exists.
236 FML_DCHECK(android_platform_view);
237 std::shared_ptr<flutter::AndroidContext> android_context =
238 android_platform_view->GetAndroidContext();
239 FML_DCHECK(android_context);
240
241 // This is a synchronous call, so the captures don't have race checks.
242 Shell::CreateCallback<PlatformView> on_create_platform_view =
243 [&jni_facade, android_context, &weak_platform_view](Shell& shell) {
244 std::unique_ptr<PlatformViewAndroid> platform_view_android;
245 platform_view_android = std::make_unique<PlatformViewAndroid>(
246 shell, // delegate
247 shell.GetTaskRunners(), // task runners
248 jni_facade, // JNI interop
249 android_context // Android context
250 );
251 weak_platform_view = platform_view_android->GetWeakPtr();
252 return platform_view_android;
253 };
254
255 Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
256 return std::make_unique<Rasterizer>(shell);
257 };
258
259 // TODO(xster): could be worth tracing this to investigate whether
260 // the IsolateConfiguration could be cached somewhere.
261 auto config = BuildRunConfiguration(entrypoint, libraryUrl, entrypoint_args);
262 if (!config) {
263 // If the RunConfiguration was null, the kernel blob wasn't readable.
264 // Fail the whole thing.
265 return nullptr;
266 }
267
268 std::unique_ptr<flutter::Shell> shell =
269 shell_->Spawn(std::move(config.value()), initial_route,
270 on_create_platform_view, on_create_rasterizer);
271
272 return std::unique_ptr<AndroidShellHolder>(new AndroidShellHolder(
273 GetSettings(), jni_facade, thread_host_, std::move(shell),
274 apk_asset_provider_->Clone(), weak_platform_view));
275}
276
278 std::unique_ptr<APKAssetProvider> apk_asset_provider,
279 const std::string& entrypoint,
280 const std::string& libraryUrl,
281 const std::vector<std::string>& entrypoint_args) {
282 if (!IsValid()) {
283 return;
284 }
285
286 apk_asset_provider_ = std::move(apk_asset_provider);
287 auto config = BuildRunConfiguration(entrypoint, libraryUrl, entrypoint_args);
288 if (!config) {
289 return;
290 }
292 shell_->RunEngine(std::move(config.value()));
293}
294
297 bool base64_encode) {
298 if (!IsValid()) {
299 return {nullptr, SkISize::MakeEmpty(), "",
301 }
302 return shell_->Screenshot(type, base64_encode);
303}
304
306 FML_DCHECK(platform_view_);
307 return platform_view_;
308}
309
311 FML_DCHECK(shell_);
312 shell_->NotifyLowMemoryWarning();
313}
314
315std::optional<RunConfiguration> AndroidShellHolder::BuildRunConfiguration(
316 const std::string& entrypoint,
317 const std::string& libraryUrl,
318 const std::vector<std::string>& entrypoint_args) const {
319 std::unique_ptr<IsolateConfiguration> isolate_configuration;
321 isolate_configuration = IsolateConfiguration::CreateForAppSnapshot();
322 } else {
323 std::unique_ptr<fml::Mapping> kernel_blob =
325 GetSettings().application_kernel_asset);
326 if (!kernel_blob) {
327 FML_DLOG(ERROR) << "Unable to load the kernel blob asset.";
328 return std::nullopt;
329 }
330 isolate_configuration =
331 IsolateConfiguration::CreateForKernel(std::move(kernel_blob));
332 }
333
334 RunConfiguration config(std::move(isolate_configuration));
335 config.AddAssetResolver(apk_asset_provider_->Clone());
336
337 {
338 if (!entrypoint.empty() && !libraryUrl.empty()) {
339 config.SetEntrypointAndLibrary(entrypoint, libraryUrl);
340 } else if (!entrypoint.empty()) {
341 config.SetEntrypoint(entrypoint);
342 }
343 if (!entrypoint_args.empty()) {
344 config.SetEntrypointArgs(entrypoint_args);
345 }
346 }
347 return config;
348}
349
351 std::vector<std::unique_ptr<Display>> displays;
352 displays.push_back(std::make_unique<AndroidDisplay>(jni_facade_));
353 shell_->OnDisplayUpdates(std::move(displays));
354}
355
356} // namespace flutter
std::unique_ptr< flutter::PlatformViewIOS > platform_view
static std::shared_ptr< ImageGenerator > MakeFromData(sk_sp< SkData > data, const fml::RefPtr< fml::TaskRunner > &task_runner)
This is the Android owner of the core engine Shell.
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:167
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition shell.h:119
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
Definition mapping.cc:20
static void EnsureInitializedForCurrentThread()
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
@ 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
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()
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 ref_ptr.h:256
static constexpr SkISize MakeEmpty()
Definition SkSize.h:22
std::string lifecycle_state
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.
The ThreadConfig is the thread info include thread name, thread priority.
Definition thread.h:35
ThreadPriority priority
Definition thread.h:45
#define ERROR(message)