engine.cc 16.7 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 flutter {
30

31 32 33 34 35
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";
36
static constexpr char kIsolateChannel[] = "flutter/isolate";
37 38

Engine::Engine(Delegate& delegate,
39
               const PointerDataDispatcherMaker& dispatcher_maker,
40 41 42 43
               DartVM& vm,
               fml::RefPtr<const DartSnapshot> isolate_snapshot,
               TaskRunners task_runners,
               Settings settings,
44
               std::unique_ptr<Animator> animator,
45 46
               fml::WeakPtr<IOManager> io_manager,
               fml::RefPtr<SkiaUnrefQueue> unref_queue)
47 48 49
    : delegate_(delegate),
      settings_(std::move(settings)),
      animator_(std::move(animator)),
50
      activity_running_(true),
51
      have_surface_(false),
52 53 54
      image_decoder_(task_runners,
                     vm.GetConcurrentWorkerTaskRunner(),
                     io_manager),
55
      task_runners_(std::move(task_runners)),
56 57 58 59
      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.
60
  runtime_controller_ = std::make_unique<RuntimeController>(
61 62 63
      *this,                                 // runtime delegate
      &vm,                                   // VM
      std::move(isolate_snapshot),           // isolate snapshot
64
      task_runners_,                         // task runners
65
      std::move(io_manager),                 // io manager
66
      std::move(unref_queue),                // Skia unref queue
67
      image_decoder_.GetWeakPtr(),           // image decoder
68 69
      settings_.advisory_script_uri,         // advisory script uri
      settings_.advisory_script_entrypoint,  // advisory script entrypoint
70 71
      settings_.idle_notification_callback,  // idle notification callback
      settings_.isolate_create_callback,     // isolate create callback
72 73
      settings_.isolate_shutdown_callback,   // isolate shutdown callback
      settings_.persistent_isolate_data      // persistent isolate data
74
  );
75 76

  pointer_data_dispatcher_ = dispatcher_maker(*this);
77 78
}

J
Jason Simmons 已提交
79
Engine::~Engine() = default;
80

81 82 83 84
float Engine::GetDisplayRefreshRate() const {
  return animator_->GetDisplayRefreshRate();
}

85
fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
86
  return weak_factory_.GetWeakPtr();
87 88 89
}

bool Engine::UpdateAssetManager(
90
    std::shared_ptr<AssetManager> new_asset_manager) {
91 92
  if (asset_manager_ == new_asset_manager) {
    return false;
R
Ryan Macnak 已提交
93 94
  }

95
  asset_manager_ = new_asset_manager;
96

97 98
  if (!asset_manager_) {
    return false;
99 100
  }

J
Jason Simmons 已提交
101
  // Using libTXT as the text engine.
102 103
  font_collection_.RegisterFonts(asset_manager_);

J
Jason Simmons 已提交
104
  if (settings_.use_test_fonts) {
105
    font_collection_.RegisterTestFonts();
106 107
  }

108 109
  return true;
}
110

111
bool Engine::Restart(RunConfiguration configuration) {
112
  TRACE_EVENT0("flutter", "Engine::Restart");
113
  if (!configuration.IsValid()) {
114
    FML_LOG(ERROR) << "Engine run configuration was invalid.";
115
    return false;
116
  }
117
  delegate_.OnPreEngineRestart();
118 119
  runtime_controller_ = runtime_controller_->Clone();
  UpdateAssetManager(nullptr);
120
  return Run(std::move(configuration)) == Engine::RunStatus::Success;
121
}
122

123
Engine::RunStatus Engine::Run(RunConfiguration configuration) {
124
  if (!configuration.IsValid()) {
125
    FML_LOG(ERROR) << "Engine run configuration was invalid.";
126
    return RunStatus::Failure;
127
  }
R
Ryan Macnak 已提交
128

129 130 131
  last_entry_point_ = configuration.GetEntrypoint();
  last_entry_point_library_ = configuration.GetEntrypointLibrary();

132 133 134
  auto isolate_launch_status =
      PrepareAndLaunchIsolate(std::move(configuration));
  if (isolate_launch_status == Engine::RunStatus::Failure) {
135
    FML_LOG(ERROR) << "Engine not prepare and launch isolate.";
136 137 138 139
    return isolate_launch_status;
  } else if (isolate_launch_status ==
             Engine::RunStatus::FailureAlreadyRunning) {
    return isolate_launch_status;
140
  }
R
Ryan Macnak 已提交
141

142
  std::shared_ptr<DartIsolate> isolate =
143
      runtime_controller_->GetRootIsolate().lock();
R
Ryan Macnak 已提交
144

145
  bool isolate_running =
146
      isolate && isolate->GetPhase() == DartIsolate::Phase::Running;
R
Ryan Macnak 已提交
147

148 149
  if (isolate_running) {
    tonic::DartState::Scope scope(isolate.get());
150

151 152 153
    if (settings_.root_isolate_create_callback) {
      settings_.root_isolate_create_callback();
    }
154

155 156 157 158
    if (settings_.root_isolate_shutdown_callback) {
      isolate->AddIsolateShutdownCallback(
          settings_.root_isolate_shutdown_callback);
    }
159 160 161 162 163 164 165 166

    std::string service_id = isolate->GetServiceId();
    fml::RefPtr<PlatformMessage> service_id_message =
        fml::MakeRefCounted<flutter::PlatformMessage>(
            kIsolateChannel,
            std::vector<uint8_t>(service_id.begin(), service_id.end()),
            nullptr);
    HandlePlatformMessage(service_id_message);
167
  }
168

169 170
  return isolate_running ? Engine::RunStatus::Success
                         : Engine::RunStatus::Failure;
171 172
}

173
Engine::RunStatus Engine::PrepareAndLaunchIsolate(
174
    RunConfiguration configuration) {
175
  TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate");
176

177
  UpdateAssetManager(configuration.GetAssetManager());
178

179 180
  auto isolate_configuration = configuration.TakeIsolateConfiguration();

181
  std::shared_ptr<DartIsolate> isolate =
182
      runtime_controller_->GetRootIsolate().lock();
183

184
  if (!isolate) {
185 186 187 188 189
    return RunStatus::Failure;
  }

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

  if (!isolate_configuration->PrepareIsolate(*isolate)) {
196
    FML_LOG(ERROR) << "Could not prepare to run the isolate.";
197
    return RunStatus::Failure;
198 199
  }

200
  if (configuration.GetEntrypointLibrary().empty()) {
201 202
    if (!isolate->Run(configuration.GetEntrypoint(),
                      settings_.dart_entrypoint_args)) {
203
      FML_LOG(ERROR) << "Could not run the isolate.";
204
      return RunStatus::Failure;
205 206 207
    }
  } else {
    if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(),
208 209
                                 configuration.GetEntrypoint(),
                                 settings_.dart_entrypoint_args)) {
210
      FML_LOG(ERROR) << "Could not run the isolate.";
211
      return RunStatus::Failure;
212
    }
213
  }
214

215
  return RunStatus::Success;
216 217
}

218
void Engine::BeginFrame(fml::TimePoint frame_time) {
219
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
220
  runtime_controller_->BeginFrame(frame_time);
A
Adam Barth 已提交
221 222
}

223
void Engine::ReportTimings(std::vector<int64_t> timings) {
224
  TRACE_EVENT0("flutter", "Engine::ReportTimings");
225 226 227
  runtime_controller_->ReportTimings(std::move(timings));
}

228
void Engine::NotifyIdle(int64_t deadline) {
229
  auto trace_event = std::to_string(deadline - Dart_TimelineGetMicros());
230
  TRACE_EVENT1("flutter", "Engine::NotifyIdle", "deadline_now_delta",
231
               trace_event.c_str());
232
  runtime_controller_->NotifyIdle(deadline);
233 234
}

235 236
std::pair<bool, uint32_t> Engine::GetUIIsolateReturnCode() {
  return runtime_controller_->GetRootIsolateReturnCode();
237 238
}

239
Dart_Port Engine::GetUIIsolateMainPort() {
240
  return runtime_controller_->GetMainPort();
241 242
}

243
std::string Engine::GetUIIsolateName() {
244
  return runtime_controller_->GetIsolateName();
245 246
}

247
bool Engine::UIIsolateHasLivePorts() {
248
  return runtime_controller_->HasLivePorts();
249 250
}

251
tonic::DartErrorHandleType Engine::GetUIIsolateLastError() {
252
  return runtime_controller_->GetLastError();
253 254
}

255
void Engine::OnOutputSurfaceCreated() {
256 257
  have_surface_ = true;
  StartAnimatorIfPossible();
258
  ScheduleFrame();
259 260
}

261
void Engine::OnOutputSurfaceDestroyed() {
262 263
  have_surface_ = false;
  StopAnimator();
264 265
}

266
void Engine::SetViewportMetrics(const ViewportMetrics& metrics) {
267 268
  bool dimensions_changed =
      viewport_metrics_.physical_height != metrics.physical_height ||
269 270
      viewport_metrics_.physical_width != metrics.physical_width ||
      viewport_metrics_.physical_depth != metrics.physical_depth;
271
  viewport_metrics_ = metrics;
272
  runtime_controller_->SetViewportMetrics(viewport_metrics_);
273
  if (animator_) {
274 275
    if (dimensions_changed)
      animator_->SetDimensionChangePending();
276 277 278
    if (have_surface_)
      ScheduleFrame();
  }
279 280
}

281
void Engine::DispatchPlatformMessage(fml::RefPtr<PlatformMessage> message) {
282 283 284 285
  if (message->channel() == kLifecycleChannel) {
    if (HandleLifecyclePlatformMessage(message.get()))
      return;
  } else if (message->channel() == kLocalizationChannel) {
286 287
    if (HandleLocalizationPlatformMessage(message.get()))
      return;
288 289 290
  } else if (message->channel() == kSettingsChannel) {
    HandleSettingsPlatformMessage(message.get());
    return;
291 292
  }

293 294
  if (runtime_controller_->IsRootIsolateRunning() &&
      runtime_controller_->DispatchPlatformMessage(std::move(message))) {
295 296 297
    return;
  }

298
  // If there's no runtime_, we may still need to set the initial route.
299
  if (message->channel() == kNavigationChannel) {
300
    HandleNavigationPlatformMessage(std::move(message));
301 302 303 304 305
    return;
  }

  FML_DLOG(WARNING) << "Dropping platform message on channel: "
                    << message->channel();
306 307
}

308
bool Engine::HandleLifecyclePlatformMessage(PlatformMessage* message) {
309 310
  const auto& data = message->data();
  std::string state(reinterpret_cast<const char*>(data.data()), data.size());
311 312
  if (state == "AppLifecycleState.paused" ||
      state == "AppLifecycleState.suspending") {
313 314
    activity_running_ = false;
    StopAnimator();
315
  } else if (state == "AppLifecycleState.resumed" ||
316
             state == "AppLifecycleState.inactive") {
317 318 319
    activity_running_ = true;
    StartAnimatorIfPossible();
  }
320 321

  // Always schedule a frame when the app does become active as per API
322 323
  // recommendation
  // https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive?language=objc
324 325 326
  if (state == "AppLifecycleState.resumed" && have_surface_) {
    ScheduleFrame();
  }
327 328
  runtime_controller_->SetLifecycleState(state);
  // Always forward these messages to the framework by returning false.
329 330 331 332
  return false;
}

bool Engine::HandleNavigationPlatformMessage(
333
    fml::RefPtr<PlatformMessage> message) {
334 335 336 337 338 339 340 341
  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");
342
  if (method->value != "setInitialRoute")
343
    return false;
344 345
  auto route = root.FindMember("args");
  initial_route_ = std::move(route->value.GetString());
346 347 348
  return true;
}

349
bool Engine::HandleLocalizationPlatformMessage(PlatformMessage* message) {
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
  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;

365 366
  const size_t strings_per_locale = 4;
  if (args->value.Size() % strings_per_locale != 0)
367
    return false;
368 369 370 371 372 373 374 375 376 377 378
  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());
  }
379

380
  return runtime_controller_->SetLocales(locale_data);
A
Adam Barth 已提交
381 382
}

383
void Engine::HandleSettingsPlatformMessage(PlatformMessage* message) {
384
  const auto& data = message->data();
385
  std::string jsonData(reinterpret_cast<const char*>(data.data()), data.size());
386 387 388
  if (runtime_controller_->SetUserSettingsData(std::move(jsonData)) &&
      have_surface_) {
    ScheduleFrame();
389 390 391
  }
}

392 393 394
void Engine::DispatchPointerDataPacket(
    std::unique_ptr<PointerDataPacket> packet,
    uint64_t trace_flow_id) {
395 396
  TRACE_EVENT0("flutter", "Engine::DispatchPointerDataPacket");
  TRACE_FLOW_STEP("flutter", "PointerEvent", trace_flow_id);
397
  pointer_data_dispatcher_->DispatchPacket(std::move(packet), trace_flow_id);
398 399
}

400
void Engine::DispatchSemanticsAction(int id,
401
                                     SemanticsAction action,
402
                                     std::vector<uint8_t> args) {
403
  runtime_controller_->DispatchSemanticsAction(id, action, std::move(args));
404 405 406
}

void Engine::SetSemanticsEnabled(bool enabled) {
407
  runtime_controller_->SetSemanticsEnabled(enabled);
408 409
}

410 411
void Engine::SetAccessibilityFeatures(int32_t flags) {
  runtime_controller_->SetAccessibilityFeatures(flags);
412 413
}

414 415 416 417 418 419 420 421 422
void Engine::StopAnimator() {
  animator_->Stop();
}

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

423 424 425 426 427 428 429
std::string Engine::DefaultRouteName() {
  if (!initial_route_.empty()) {
    return initial_route_;
  }
  return "/";
}

430 431
void Engine::ScheduleFrame(bool regenerate_layer_tree) {
  animator_->RequestFrame(regenerate_layer_tree);
A
Adam Barth 已提交
432 433
}

434
void Engine::Render(std::unique_ptr<flutter::LayerTree> layer_tree) {
435 436
  if (!layer_tree)
    return;
437

438 439 440
  SkISize frame_size = SkISize::Make(viewport_metrics_.physical_width,
                                     viewport_metrics_.physical_height);
  if (frame_size.isEmpty())
441 442
    return;

443
  layer_tree->set_frame_size(frame_size);
444
  layer_tree->set_device_pixel_ratio(viewport_metrics_.device_pixel_ratio);
445 446
  animator_->Render(std::move(layer_tree));
}
447

448 449
void Engine::UpdateSemantics(SemanticsNodeUpdates update,
                             CustomAccessibilityActionUpdates actions) {
450
  delegate_.OnEngineUpdateSemantics(std::move(update), std::move(actions));
451
}
452

453
void Engine::HandlePlatformMessage(fml::RefPtr<PlatformMessage> message) {
454
  if (message->channel() == kAssetChannel) {
A
Adam Barth 已提交
455
    HandleAssetPlatformMessage(std::move(message));
456
  } else {
457
    delegate_.OnEngineHandlePlatformMessage(std::move(message));
A
Adam Barth 已提交
458
  }
459 460
}

461 462 463 464 465
void Engine::UpdateIsolateDescription(const std::string isolate_name,
                                      int64_t isolate_port) {
  delegate_.UpdateIsolateDescription(isolate_name, isolate_port);
}

466 467
void Engine::SetNeedsReportTimings(bool needs_reporting) {
  delegate_.SetNeedsReportTimings(needs_reporting);
468 469
}

470
FontCollection& Engine::GetFontCollection() {
471 472 473
  return font_collection_;
}

474 475 476 477 478 479 480 481 482 483 484 485
void Engine::DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
                              uint64_t trace_flow_id) {
  animator_->EnqueueTraceFlowId(trace_flow_id);
  if (runtime_controller_) {
    runtime_controller_->DispatchPointerDataPacket(*packet);
  }
}

void Engine::ScheduleSecondaryVsyncCallback(fml::closure callback) {
  animator_->ScheduleSecondaryVsyncCallback(std::move(callback));
}

486 487
void Engine::HandleAssetPlatformMessage(fml::RefPtr<PlatformMessage> message) {
  fml::RefPtr<PlatformMessageResponse> response = message->response();
488
  if (!response) {
A
Adam Barth 已提交
489
    return;
490
  }
A
Adam Barth 已提交
491 492 493
  const auto& data = message->data();
  std::string asset_name(reinterpret_cast<const char*>(data.data()),
                         data.size());
494

495 496 497 498 499 500 501
  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 已提交
502
  }
503 504

  response->CompleteEmpty();
A
Adam Barth 已提交
505 506
}

507 508 509 510 511 512 513 514
const std::string& Engine::GetLastEntrypoint() const {
  return last_entry_point_;
}

const std::string& Engine::GetLastEntrypointLibrary() const {
  return last_entry_point_library_;
}

515
}  // namespace flutter