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/logging.h"
20 #include "flutter/fml/make_copyable.h"
21 #include "flutter/fml/message_loop.h"
22 #include "flutter/fml/native_library.h"
23 #include "flutter/fml/platform/android/jni_util.h"
24 #include "flutter/lib/ui/painting/image_generator_registry.h"
25 #include "flutter/shell/common/rasterizer.h"
26 #include "flutter/shell/common/run_configuration.h"
27 #include "flutter/shell/common/thread_host.h"
28 #include "flutter/shell/platform/android/android_image_generator.h"
29 #include "flutter/shell/platform/android/context/android_context.h"
30 #include "flutter/shell/platform/android/platform_view_android.h"
31 
32 namespace flutter {
33 
35  PlatformData platform_data;
36  platform_data.lifecycle_state = "AppLifecycleState.detached";
37  return platform_data;
38 }
39 
41  flutter::Settings settings,
42  std::shared_ptr<PlatformViewAndroidJNI> jni_facade)
43  : settings_(std::move(settings)), jni_facade_(jni_facade) {
44  static size_t thread_host_count = 1;
45  auto thread_label = std::to_string(thread_host_count++);
46 
47  thread_host_ = std::make_shared<ThreadHost>();
48  *thread_host_ = {thread_label, ThreadHost::Type::UI |
49  ThreadHost::Type::RASTER |
50  ThreadHost::Type::IO};
51 
52  fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
53  Shell::CreateCallback<PlatformView> on_create_platform_view =
54  [&jni_facade, &weak_platform_view](Shell& shell) {
55  std::unique_ptr<PlatformViewAndroid> platform_view_android;
56  platform_view_android = std::make_unique<PlatformViewAndroid>(
57  shell, // delegate
58  shell.GetTaskRunners(), // task runners
59  jni_facade, // JNI interop
60  shell.GetSettings()
61  .enable_software_rendering // use software rendering
62  );
63  weak_platform_view = platform_view_android->GetWeakPtr();
64  auto display = Display(jni_facade->GetDisplayRefreshRate());
65  shell.OnDisplayUpdates(DisplayUpdateType::kStartup, {display});
66  return platform_view_android;
67  };
68 
69  Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
70  return std::make_unique<Rasterizer>(shell);
71  };
72 
73  // The current thread will be used as the platform thread. Ensure that the
74  // message loop is initialized.
76  fml::RefPtr<fml::TaskRunner> raster_runner;
79  fml::RefPtr<fml::TaskRunner> platform_runner =
81  raster_runner = thread_host_->raster_thread->GetTaskRunner();
82  ui_runner = thread_host_->ui_thread->GetTaskRunner();
83  io_runner = thread_host_->io_thread->GetTaskRunner();
84 
85  flutter::TaskRunners task_runners(thread_label, // label
86  platform_runner, // platform
87  raster_runner, // raster
88  ui_runner, // ui
89  io_runner // io
90  );
91  task_runners.GetRasterTaskRunner()->PostTask([]() {
92  // Android describes -8 as "most important display threads, for
93  // compositing the screen and retrieving input events". Conservatively
94  // set the raster thread to slightly lower priority than it.
95  if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) {
96  // Defensive fallback. Depending on the OEM, it may not be possible
97  // to set priority to -5.
98  if (::setpriority(PRIO_PROCESS, gettid(), -2) != 0) {
99  FML_LOG(ERROR) << "Failed to set raster task runner priority";
100  }
101  }
102  });
103  task_runners.GetUITaskRunner()->PostTask([]() {
104  if (::setpriority(PRIO_PROCESS, gettid(), -1) != 0) {
105  FML_LOG(ERROR) << "Failed to set UI task runner priority";
106  }
107  });
108  task_runners.GetIOTaskRunner()->PostTask([]() {
109  if (::setpriority(PRIO_PROCESS, gettid(), 1) != 0) {
110  FML_LOG(ERROR) << "Failed to set IO task runner priority";
111  }
112  });
113 
114  shell_ =
115  Shell::Create(GetDefaultPlatformData(), // window data
116  task_runners, // task runners
117  settings_, // settings
118  on_create_platform_view, // platform view create callback
119  on_create_rasterizer // rasterizer create callback
120  );
121 
122  if (shell_) {
123  shell_->GetDartVM()->GetConcurrentMessageLoop()->PostTaskToAllWorkers([]() {
124  if (::setpriority(PRIO_PROCESS, gettid(), 1) != 0) {
125  FML_LOG(ERROR) << "Failed to set Workers task runner priority";
126  }
127  });
128 
129  shell_->RegisterImageDecoder(
130  [runner = task_runners.GetIOTaskRunner()](sk_sp<SkData> buffer) {
132  },
133  -1);
134  FML_DLOG(INFO) << "Registered Android SDK image decoder (API level 28+)";
135  }
136 
137  platform_view_ = weak_platform_view;
138  FML_DCHECK(platform_view_);
139  is_valid_ = shell_ != nullptr;
140 }
141 
143  const Settings& settings,
144  const std::shared_ptr<PlatformViewAndroidJNI>& jni_facade,
145  const std::shared_ptr<ThreadHost>& thread_host,
146  std::unique_ptr<Shell> shell,
148  : settings_(std::move(settings)),
149  jni_facade_(jni_facade),
150  platform_view_(platform_view),
151  thread_host_(thread_host),
152  shell_(std::move(shell)) {
153  FML_DCHECK(jni_facade);
154  FML_DCHECK(shell_);
155  FML_DCHECK(shell_->IsSetup());
156  FML_DCHECK(platform_view_);
157  FML_DCHECK(thread_host_);
158  is_valid_ = shell_ != nullptr;
159 }
160 
162  shell_.reset();
163  thread_host_.reset();
164 }
165 
167  return is_valid_;
168 }
169 
171  return settings_;
172 }
173 
174 std::unique_ptr<AndroidShellHolder> AndroidShellHolder::Spawn(
175  std::shared_ptr<PlatformViewAndroidJNI> jni_facade,
176  const std::string& entrypoint,
177  const std::string& libraryUrl,
178  const std::string& initial_route) const {
179  FML_DCHECK(shell_ && shell_->IsSetup())
180  << "A new Shell can only be spawned "
181  "if the current Shell is properly constructed";
182 
183  // Pull out the new PlatformViewAndroid from the new Shell to feed to it to
184  // the new AndroidShellHolder.
185  //
186  // It's a weak pointer because it's owned by the Shell (which we're also)
187  // making below. And the AndroidShellHolder then owns the Shell.
188  fml::WeakPtr<PlatformViewAndroid> weak_platform_view;
189 
190  // Take out the old AndroidContext to reuse inside the PlatformViewAndroid
191  // of the new Shell.
192  PlatformViewAndroid* android_platform_view = platform_view_.get();
193  // There's some indirection with platform_view_ being a weak pointer but
194  // we just checked that the shell_ exists above and a valid shell is the
195  // owner of the platform view so this weak pointer always exists.
196  FML_DCHECK(android_platform_view);
197  std::shared_ptr<flutter::AndroidContext> android_context =
198  android_platform_view->GetAndroidContext();
199  FML_DCHECK(android_context);
200 
201  // This is a synchronous call, so the captures don't have race checks.
202  Shell::CreateCallback<PlatformView> on_create_platform_view =
203  [&jni_facade, android_context, &weak_platform_view](Shell& shell) {
204  std::unique_ptr<PlatformViewAndroid> platform_view_android;
205  platform_view_android = std::make_unique<PlatformViewAndroid>(
206  shell, // delegate
207  shell.GetTaskRunners(), // task runners
208  jni_facade, // JNI interop
209  android_context // Android context
210  );
211  weak_platform_view = platform_view_android->GetWeakPtr();
212  auto display = Display(jni_facade->GetDisplayRefreshRate());
213  shell.OnDisplayUpdates(DisplayUpdateType::kStartup, {display});
214  return platform_view_android;
215  };
216 
217  Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
218  return std::make_unique<Rasterizer>(shell);
219  };
220 
221  // TODO(xster): could be worth tracing this to investigate whether
222  // the IsolateConfiguration could be cached somewhere.
223  auto config = BuildRunConfiguration(asset_manager_, entrypoint, libraryUrl);
224  if (!config) {
225  // If the RunConfiguration was null, the kernel blob wasn't readable.
226  // Fail the whole thing.
227  return nullptr;
228  }
229 
230  std::unique_ptr<flutter::Shell> shell =
231  shell_->Spawn(std::move(config.value()), initial_route,
232  on_create_platform_view, on_create_rasterizer);
233 
234  return std::unique_ptr<AndroidShellHolder>(
235  new AndroidShellHolder(GetSettings(), jni_facade, thread_host_,
236  std::move(shell), weak_platform_view));
237 }
238 
239 void AndroidShellHolder::Launch(std::shared_ptr<AssetManager> asset_manager,
240  const std::string& entrypoint,
241  const std::string& libraryUrl) {
242  if (!IsValid()) {
243  return;
244  }
245 
246  asset_manager_ = asset_manager;
247  auto config = BuildRunConfiguration(asset_manager, entrypoint, libraryUrl);
248  if (!config) {
249  return;
250  }
251  shell_->RunEngine(std::move(config.value()));
252 }
253 
256  bool base64_encode) {
257  if (!IsValid()) {
258  return {nullptr, SkISize::MakeEmpty()};
259  }
260  return shell_->Screenshot(type, base64_encode);
261 }
262 
264  FML_DCHECK(platform_view_);
265  return platform_view_;
266 }
267 
269  FML_DCHECK(shell_);
270  shell_->NotifyLowMemoryWarning();
271 }
272 
273 std::optional<RunConfiguration> AndroidShellHolder::BuildRunConfiguration(
274  std::shared_ptr<flutter::AssetManager> asset_manager,
275  const std::string& entrypoint,
276  const std::string& libraryUrl) const {
277  std::unique_ptr<IsolateConfiguration> isolate_configuration;
279  isolate_configuration = IsolateConfiguration::CreateForAppSnapshot();
280  } else {
281  std::unique_ptr<fml::Mapping> kernel_blob =
283  GetSettings().application_kernel_asset);
284  if (!kernel_blob) {
285  FML_DLOG(ERROR) << "Unable to load the kernel blob asset.";
286  return std::nullopt;
287  }
288  isolate_configuration =
289  IsolateConfiguration::CreateForKernel(std::move(kernel_blob));
290  }
291 
292  RunConfiguration config(std::move(isolate_configuration),
293  std::move(asset_manager));
294 
295  {
296  if ((entrypoint.size() > 0) && (libraryUrl.size() > 0)) {
297  config.SetEntrypointAndLibrary(std::move(entrypoint),
298  std::move(libraryUrl));
299  } else if (entrypoint.size() > 0) {
300  config.SetEntrypoint(std::move(entrypoint));
301  }
302  }
303  return config;
304 }
305 
306 } // namespace flutter
KeyCallType type
std::function< std::unique_ptr< T >(Shell &)> CreateCallback
Definition: shell.h:114
const std::shared_ptr< AndroidContext > & GetAndroidContext()
#define FML_DCHECK(condition)
Definition: logging.h:86
std::unique_ptr< flutter::PlatformViewIOS > platform_view
Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, bool base64_encode)
static std::unique_ptr< IsolateConfiguration > CreateForAppSnapshot()
Creates an AOT isolate configuration using snapshot symbols present in the currently loaded process...
static std::shared_ptr< ImageGenerator > MakeFromData(sk_sp< SkData > data, fml::RefPtr< fml::TaskRunner > task_runner)
Definition: ref_ptr.h:252
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
Definition: message_loop.cc:19
static void EnsureInitializedForCurrentThread()
Definition: message_loop.cc:27
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
This is a factory for a derived AndroidShellHolder from an existing AndroidShellHolder.
#define FML_LOG(severity)
Definition: logging.h:65
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...
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
Definition: message_loop.cc:56
void SetEntrypoint(std::string entrypoint)
Updates the main application entrypoint. If this is not set, the "main" method is used as the entrypo...
A POD type used to return the screenshot data along with the size of the frame.
Definition: rasterizer.h:275
ScreenshotType
The type of the screenshot to obtain of the previously rendered layer tree.
Definition: rasterizer.h:245
Specifies all the configuration required by the runtime library to launch the root isolate...
void Launch(std::shared_ptr< AssetManager > asset_manager, const std::string &entrypoint, const std::string &libraryUrl)
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:202
AndroidShellHolder(flutter::Settings settings, std::shared_ptr< PlatformViewAndroidJNI > jni_facade)
void SetEntrypointAndLibrary(std::string entrypoint, std::string library)
Specifies the main Dart entrypoint and the library to find that entrypoint in. By default...
fml::WeakPtr< PlatformViewAndroid > GetPlatformView()
static std::unique_ptr< Shell > Create(const PlatformData &platform_data, 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:126
const flutter::Settings & GetSettings() const
fml::RefPtr< fml::TaskRunner > GetIOTaskRunner() const
Definition: task_runners.cc:38
fml::RefPtr< fml::TaskRunner > GetUITaskRunner() const
Definition: task_runners.cc:34
static PlatformData GetDefaultPlatformData()
static const uint8_t buffer[]
#define FML_DLOG(severity)
Definition: logging.h:85
static std::unique_ptr< FileMapping > CreateReadOnly(const std::string &path)
Definition: mapping.cc:18
Settings settings_
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24
std::string lifecycle_state
Definition: platform_data.h:40