engine.cc 14.5 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "flutter/shell/common/engine.h"
6

7
#include <memory>
8
#include <string>
9
#include <utility>
10
#include <vector>
11

12
#include "flutter/common/settings.h"
13 14 15 16
#include "flutter/fml/eintr_wrapper.h"
#include "flutter/fml/file.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/paths.h"
17
#include "flutter/fml/trace_event.h"
18
#include "flutter/fml/unique_fd.h"
R
Ryan Macnak 已提交
19
#include "flutter/lib/snapshot/snapshot.h"
20
#include "flutter/lib/ui/text/font_collection.h"
21
#include "flutter/shell/common/animator.h"
22
#include "flutter/shell/common/platform_view.h"
23
#include "flutter/shell/common/shell.h"
24
#include "rapidjson/document.h"
25
#include "third_party/dart/runtime/include/dart_tools_api.h"
A
Adam Barth 已提交
26 27
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
28

29
namespace shell {
30

31 32 33 34 35 36 37
static constexpr char kAssetChannel[] = "flutter/assets";
static constexpr char kLifecycleChannel[] = "flutter/lifecycle";
static constexpr char kNavigationChannel[] = "flutter/navigation";
static constexpr char kLocalizationChannel[] = "flutter/localization";
static constexpr char kSettingsChannel[] = "flutter/settings";

Engine::Engine(Delegate& delegate,
B
Ben Konyi 已提交
38
               blink::DartVM& vm,
39 40
               fml::RefPtr<blink::DartSnapshot> isolate_snapshot,
               fml::RefPtr<blink::DartSnapshot> shared_snapshot,
41 42 43
               blink::TaskRunners task_runners,
               blink::Settings settings,
               std::unique_ptr<Animator> animator,
44
               fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate,
45
               fml::WeakPtr<GrContext> resource_context,
46
               fml::RefPtr<flow::SkiaUnrefQueue> unref_queue)
47 48 49
    : delegate_(delegate),
      settings_(std::move(settings)),
      animator_(std::move(animator)),
50 51
      activity_running_(false),
      have_surface_(false),
52 53 54 55 56
      weak_factory_(this) {
  // Runtime controller is initialized here because it takes a reference to this
  // object as its delegate. The delegate may be called in the constructor and
  // we want to be fully initilazed by that point.
  runtime_controller_ = std::make_unique<blink::RuntimeController>(
57 58 59 60 61
      *this,                                // runtime delegate
      &vm,                                  // VM
      std::move(isolate_snapshot),          // isolate snapshot
      std::move(shared_snapshot),           // shared snapshot
      std::move(task_runners),              // task runners
62
      std::move(snapshot_delegate),         // snapshot delegate
63 64 65 66
      std::move(resource_context),          // resource context
      std::move(unref_queue),               // skia unref queue
      settings_.advisory_script_uri,        // advisory script uri
      settings_.advisory_script_entrypoint  // advisory script entrypoint
67
  );
68 69
}

J
Jason Simmons 已提交
70
Engine::~Engine() = default;
71

72 73 74 75
float Engine::GetDisplayRefreshRate() const {
  return animator_->GetDisplayRefreshRate();
}

76
fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
77
  return weak_factory_.GetWeakPtr();
78 79 80
}

bool Engine::UpdateAssetManager(
81
    std::shared_ptr<blink::AssetManager> new_asset_manager) {
82 83
  if (asset_manager_ == new_asset_manager) {
    return false;
R
Ryan Macnak 已提交
84 85
  }

86
  asset_manager_ = new_asset_manager;
87

88 89
  if (!asset_manager_) {
    return false;
90 91
  }

J
Jason Simmons 已提交
92 93
  // Using libTXT as the text engine.
  if (settings_.use_test_fonts) {
94
    font_collection_.RegisterTestFonts();
95
  } else {
96
    font_collection_.RegisterFonts(asset_manager_);
97 98
  }

99 100
  return true;
}
101

102 103 104
bool Engine::Restart(RunConfiguration configuration) {
  TRACE_EVENT0("flutter", "Engine::Restart");
  if (!configuration.IsValid()) {
105
    FML_LOG(ERROR) << "Engine run configuration was invalid.";
106
    return false;
107
  }
108
  delegate_.OnPreEngineRestart();
109 110
  runtime_controller_ = runtime_controller_->Clone();
  UpdateAssetManager(nullptr);
111
  return Run(std::move(configuration)) == Engine::RunStatus::Success;
112
}
113

114
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
115
  if (!configuration.IsValid()) {
116
    FML_LOG(ERROR) << "Engine run configuration was invalid.";
117
    return RunStatus::Failure;
118
  }
R
Ryan Macnak 已提交
119

120 121 122
  auto isolate_launch_status =
      PrepareAndLaunchIsolate(std::move(configuration));
  if (isolate_launch_status == Engine::RunStatus::Failure) {
123
    FML_LOG(ERROR) << "Engine not prepare and launch isolate.";
124 125 126 127
    return isolate_launch_status;
  } else if (isolate_launch_status ==
             Engine::RunStatus::FailureAlreadyRunning) {
    return isolate_launch_status;
128
  }
R
Ryan Macnak 已提交
129

130 131
  std::shared_ptr<blink::DartIsolate> isolate =
      runtime_controller_->GetRootIsolate().lock();
R
Ryan Macnak 已提交
132

133 134
  bool isolate_running =
      isolate && isolate->GetPhase() == blink::DartIsolate::Phase::Running;
R
Ryan Macnak 已提交
135

136 137
  if (isolate_running) {
    tonic::DartState::Scope scope(isolate.get());
138

139 140 141
    if (settings_.root_isolate_create_callback) {
      settings_.root_isolate_create_callback();
    }
142

143 144 145 146
    if (settings_.root_isolate_shutdown_callback) {
      isolate->AddIsolateShutdownCallback(
          settings_.root_isolate_shutdown_callback);
    }
147
  }
148

149 150
  return isolate_running ? Engine::RunStatus::Success
                         : Engine::RunStatus::Failure;
151 152
}

153 154
shell::Engine::RunStatus Engine::PrepareAndLaunchIsolate(
    RunConfiguration configuration) {
155
  TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate");
156

157
  UpdateAssetManager(configuration.GetAssetManager());
158

159 160
  auto isolate_configuration = configuration.TakeIsolateConfiguration();

161 162
  std::shared_ptr<blink::DartIsolate> isolate =
      runtime_controller_->GetRootIsolate().lock();
163

164
  if (!isolate) {
165 166 167 168 169 170 171 172
    return RunStatus::Failure;
  }

  // This can happen on iOS after a plugin shows a native window and returns to
  // the Flutter ViewController.
  if (isolate->GetPhase() == blink::DartIsolate::Phase::Running) {
    FML_DLOG(WARNING) << "Isolate was already running!";
    return RunStatus::FailureAlreadyRunning;
173 174 175
  }

  if (!isolate_configuration->PrepareIsolate(*isolate)) {
176
    FML_LOG(ERROR) << "Could not prepare to run the isolate.";
177
    return RunStatus::Failure;
178 179
  }

180 181
  if (configuration.GetEntrypointLibrary().empty()) {
    if (!isolate->Run(configuration.GetEntrypoint())) {
182
      FML_LOG(ERROR) << "Could not run the isolate.";
183
      return RunStatus::Failure;
184 185 186 187
    }
  } else {
    if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
                                 configuration.GetEntrypoint())) {
188
      FML_LOG(ERROR) << "Could not run the isolate.";
189
      return RunStatus::Failure;
190
    }
191
  }
192

193
  return RunStatus::Success;
194 195
}

196
void Engine::BeginFrame(fml::TimePoint frame_time) {
197
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
198
  runtime_controller_->BeginFrame(frame_time);
A
Adam Barth 已提交
199 200
}

201
void Engine::NotifyIdle(int64_t deadline) {
202 203
  TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta",
               std::to_string(deadline - Dart_TimelineGetMicros()).c_str());
204
  runtime_controller_->NotifyIdle(deadline);
205 206
}

207 208
std::pair<bool, uint32_t> Engine::GetUIIsolateReturnCode() {
  return runtime_controller_->GetRootIsolateReturnCode();
209 210
}

211
Dart_Port Engine::GetUIIsolateMainPort() {
212
  return runtime_controller_->GetMainPort();
213 214
}

215
std::string Engine::GetUIIsolateName() {
216
  return runtime_controller_->GetIsolateName();
217 218
}

219
bool Engine::UIIsolateHasLivePorts() {
220
  return runtime_controller_->HasLivePorts();
221 222
}

223
tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
224
  return runtime_controller_->GetLastError();
225 226
}

227
void Engine::OnOutputSurfaceCreated() {
228 229
  have_surface_ = true;
  StartAnimatorIfPossible();
230
  ScheduleFrame();
231 232
}

233
void Engine::OnOutputSurfaceDestroyed() {
234 235
  have_surface_ = false;
  StopAnimator();
236 237
}

238
void Engine::SetViewportMetrics(const blink::ViewportMetrics& metrics) {
239 240 241
  bool dimensions_changed =
      viewport_metrics_.physical_height != metrics.physical_height ||
      viewport_metrics_.physical_width != metrics.physical_width;
242
  viewport_metrics_ = metrics;
243
  runtime_controller_->SetViewportMetrics(viewport_metrics_);
244
  if (animator_) {
245 246
    if (dimensions_changed)
      animator_->SetDimensionChangePending();
247 248 249
    if (have_surface_)
      ScheduleFrame();
  }
250 251
}

252
void Engine::DispatchPlatformMessage(
253
    fml::RefPtr<blink::PlatformMessage> message) {
254 255 256 257
  if (message->channel() == kLifecycleChannel) {
    if (HandleLifecyclePlatformMessage(message.get()))
      return;
  } else if (message->channel() == kLocalizationChannel) {
258 259
    if (HandleLocalizationPlatformMessage(message.get()))
      return;
260 261 262
  } else if (message->channel() == kSettingsChannel) {
    HandleSettingsPlatformMessage(message.get());
    return;
263 264
  }

265 266
  if (runtime_controller_->IsRootIsolateRunning() &&
      runtime_controller_->DispatchPlatformMessage(std::move(message))) {
267 268 269
    return;
  }

270
  // If there's no runtime_, we may still need to set the initial route.
271 272
  if (message->channel() == kNavigationChannel)
    HandleNavigationPlatformMessage(std::move(message));
273 274
}

275 276 277
bool Engine::HandleLifecyclePlatformMessage(blink::PlatformMessage* message) {
  const auto& data = message->data();
  std::string state(reinterpret_cast<const char*>(data.data()), data.size());
278 279
  if (state == "AppLifecycleState.paused" ||
      state == "AppLifecycleState.suspending") {
280 281
    activity_running_ = false;
    StopAnimator();
282
  } else if (state == "AppLifecycleState.resumed" ||
283
             state == "AppLifecycleState.inactive") {
284 285 286
    activity_running_ = true;
    StartAnimatorIfPossible();
  }
287 288

  // Always schedule a frame when the app does become active as per API
289 290
  // recommendation
  // https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive?language=objc
291 292 293
  if (state == "AppLifecycleState.resumed" && have_surface_) {
    ScheduleFrame();
  }
294 295 296 297
  return false;
}

bool Engine::HandleNavigationPlatformMessage(
298
    fml::RefPtr<blink::PlatformMessage> message) {
299 300 301 302 303 304 305 306
  const auto& data = message->data();

  rapidjson::Document document;
  document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
  if (document.HasParseError() || !document.IsObject())
    return false;
  auto root = document.GetObject();
  auto method = root.FindMember("method");
307
  if (method->value != "setInitialRoute")
308
    return false;
309 310
  auto route = root.FindMember("args");
  initial_route_ = std::move(route->value.GetString());
311 312 313 314
  return true;
}

bool Engine::HandleLocalizationPlatformMessage(
315
    blink::PlatformMessage* message) {
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
  const auto& data = message->data();

  rapidjson::Document document;
  document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
  if (document.HasParseError() || !document.IsObject())
    return false;
  auto root = document.GetObject();
  auto method = root.FindMember("method");
  if (method == root.MemberEnd() || method->value != "setLocale")
    return false;

  auto args = root.FindMember("args");
  if (args == root.MemberEnd() || !args->value.IsArray())
    return false;

331 332
  const size_t strings_per_locale = 4;
  if (args->value.Size() % strings_per_locale != 0)
333
    return false;
334 335 336 337 338 339 340 341 342 343 344
  std::vector<std::string> locale_data;
  for (size_t locale_index = 0; locale_index < args->value.Size();
       locale_index += strings_per_locale) {
    if (!args->value[locale_index].IsString() ||
        !args->value[locale_index + 1].IsString())
      return false;
    locale_data.push_back(args->value[locale_index].GetString());
    locale_data.push_back(args->value[locale_index + 1].GetString());
    locale_data.push_back(args->value[locale_index + 2].GetString());
    locale_data.push_back(args->value[locale_index + 3].GetString());
  }
345

346
  return runtime_controller_->SetLocales(locale_data);
A
Adam Barth 已提交
347 348
}

349
void Engine::HandleSettingsPlatformMessage(blink::PlatformMessage* message) {
350
  const auto& data = message->data();
351
  std::string jsonData(reinterpret_cast<const char*>(data.data()), data.size());
352 353 354
  if (runtime_controller_->SetUserSettingsData(std::move(jsonData)) &&
      have_surface_) {
    ScheduleFrame();
355 356 357
  }
}

358 359
void Engine::DispatchPointerDataPacket(const blink::PointerDataPacket& packet) {
  runtime_controller_->DispatchPointerDataPacket(packet);
360 361
}

362 363 364
void Engine::DispatchSemanticsAction(int id,
                                     blink::SemanticsAction action,
                                     std::vector<uint8_t> args) {
365
  runtime_controller_->DispatchSemanticsAction(id, action, std::move(args));
366 367 368
}

void Engine::SetSemanticsEnabled(bool enabled) {
369
  runtime_controller_->SetSemanticsEnabled(enabled);
370 371
}

372 373
void Engine::SetAccessibilityFeatures(int32_t flags) {
  runtime_controller_->SetAccessibilityFeatures(flags);
374 375
}

376 377 378 379 380 381 382 383 384
void Engine::StopAnimator() {
  animator_->Stop();
}

void Engine::StartAnimatorIfPossible() {
  if (activity_running_ && have_surface_)
    animator_->Start();
}

385 386 387 388 389 390 391
std::string Engine::DefaultRouteName() {
  if (!initial_route_.empty()) {
    return initial_route_;
  }
  return "/";
}

392 393
void Engine::ScheduleFrame(bool regenerate_layer_tree) {
  animator_->RequestFrame(regenerate_layer_tree);
A
Adam Barth 已提交
394 395
}

396 397 398
void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree)
    return;
399

400 401
  SkISize frame_size = SkISize::Make(viewport_metrics_.physical_width,
                                     viewport_metrics_.physical_height);
402 403 404 405
  if (frame_size.isEmpty())
    return;

  layer_tree->set_frame_size(frame_size);
406 407
  animator_->Render(std::move(layer_tree));
}
408

409 410
void Engine::UpdateSemantics(blink::SemanticsNodeUpdates update,
                             blink::CustomAccessibilityActionUpdates actions) {
411
  delegate_.OnEngineUpdateSemantics(std::move(update), std::move(actions));
412
}
413

414
void Engine::HandlePlatformMessage(
415
    fml::RefPtr<blink::PlatformMessage> message) {
416
  if (message->channel() == kAssetChannel) {
A
Adam Barth 已提交
417
    HandleAssetPlatformMessage(std::move(message));
418
  } else {
419
    delegate_.OnEngineHandlePlatformMessage(std::move(message));
A
Adam Barth 已提交
420
  }
421 422
}

423 424 425 426 427
void Engine::UpdateIsolateDescription(const std::string isolate_name,
                                      int64_t isolate_port) {
  delegate_.UpdateIsolateDescription(isolate_name, isolate_port);
}

428 429 430 431
blink::FontCollection& Engine::GetFontCollection() {
  return font_collection_;
}

A
Adam Barth 已提交
432
void Engine::HandleAssetPlatformMessage(
433 434
    fml::RefPtr<blink::PlatformMessage> message) {
  fml::RefPtr<blink::PlatformMessageResponse> response = message->response();
435
  if (!response) {
A
Adam Barth 已提交
436
    return;
437
  }
A
Adam Barth 已提交
438 439 440
  const auto& data = message->data();
  std::string asset_name(reinterpret_cast<const char*>(data.data()),
                         data.size());
441

442 443 444 445 446 447 448
  if (asset_manager_) {
    std::unique_ptr<fml::Mapping> asset_mapping =
        asset_manager_->GetAsMapping(asset_name);
    if (asset_mapping) {
      response->Complete(std::move(asset_mapping));
      return;
    }
A
Adam Barth 已提交
449
  }
450 451

  response->CompleteEmpty();
A
Adam Barth 已提交
452 453
}

454
}  // namespace shell