engine.cc 13.0 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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 <sys/stat.h>
8
#include <unistd.h>
9 10
#include <utility>

11
#include "flutter/assets/directory_asset_bundle.h"
A
Adam Barth 已提交
12
#include "flutter/assets/unzipper_provider.h"
13
#include "flutter/assets/zip_asset_bundle.h"
14
#include "flutter/common/threads.h"
15 16
#include "flutter/glue/movable_wrapper.h"
#include "flutter/glue/trace_event.h"
17
#include "flutter/runtime/asset_font_selector.h"
18 19
#include "flutter/runtime/dart_controller.h"
#include "flutter/runtime/dart_init.h"
20
#include "flutter/runtime/runtime_init.h"
21
#include "flutter/shell/common/animator.h"
22
#include "flutter/shell/common/platform_view.h"
23
#include "flutter/sky/engine/public/web/Sky.h"
24
#include "lib/ftl/files/file.h"
25
#include "lib/ftl/files/path.h"
26
#include "lib/ftl/functional/make_copyable.h"
27
#include "mojo/public/cpp/application/connect.h"
28
#include "third_party/rapidjson/rapidjson/document.h"
A
Adam Barth 已提交
29 30
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
31 32

namespace shell {
33
namespace {
34

35 36 37 38
constexpr char kAssetChannel[] = "flutter/assets";
constexpr char kLifecycleChannel[] = "flutter/lifecycle";
constexpr char kNavigationChannel[] = "flutter/navigation";
constexpr char kLocalizationChannel[] = "flutter/localization";
A
Adam Barth 已提交
39

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
bool PathExists(const std::string& path) {
  return access(path.c_str(), R_OK) == 0;
}

std::string FindPackagesPath(const std::string& main_dart) {
  std::string directory = files::GetDirectoryName(main_dart);
  std::string packages_path = directory + "/.packages";
  if (!PathExists(packages_path)) {
    directory = files::GetDirectoryName(directory);
    packages_path = directory + "/.packages";
    if (!PathExists(packages_path))
      packages_path = std::string();
  }
  return packages_path;
}

56 57 58 59
std::string GetScriptUriFromPath(const std::string& path) {
  return "file://" + path;
}

60 61
}  // namespace

62 63
Engine::Engine(PlatformView* platform_view)
    : platform_view_(platform_view->GetWeakPtr()),
64 65 66 67
      animator_(std::make_unique<Animator>(
          platform_view->rasterizer().GetWeakRasterizerPtr(),
          platform_view->GetVsyncWaiter(),
          this)),
68
      binding_(this),
69 70
      activity_running_(false),
      have_surface_(false),
71
      weak_factory_(this) {}
72

73
Engine::~Engine() {}
74

75
ftl::WeakPtr<Engine> Engine::GetWeakPtr() {
76 77 78
  return weak_factory_.GetWeakPtr();
}

79
void Engine::Init() {
80
  blink::InitRuntime();
81 82
}

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
void Engine::RunBundle(const std::string& bundle_path) {
  TRACE_EVENT0("flutter", "Engine::RunBundle");
  ConfigureAssetBundle(bundle_path);
  ConfigureRuntime(GetScriptUriFromPath(bundle_path));
  if (blink::IsRunningPrecompiledCode()) {
    runtime_->dart_controller()->RunFromPrecompiledSnapshot();
  } else {
    std::vector<uint8_t> snapshot;
    if (!GetAssetAsBuffer(blink::kSnapshotAssetKey, &snapshot))
      return;
    runtime_->dart_controller()->RunFromSnapshot(snapshot.data(),
                                                 snapshot.size());
  }
}

void Engine::RunBundleAndSnapshot(const std::string& bundle_path,
                                  const std::string& snapshot_override) {
  TRACE_EVENT0("flutter", "Engine::RunBundleAndSnapshot");
  if (snapshot_override.empty()) {
    RunBundle(bundle_path);
    return;
  }
  ConfigureAssetBundle(bundle_path);
  ConfigureRuntime(GetScriptUriFromPath(bundle_path));
  if (blink::IsRunningPrecompiledCode()) {
    runtime_->dart_controller()->RunFromPrecompiledSnapshot();
  } else {
    std::vector<uint8_t> snapshot;
    if (!files::ReadFileToVector(snapshot_override, &snapshot))
      return;
    runtime_->dart_controller()->RunFromSnapshot(snapshot.data(),
                                                 snapshot.size());
  }
}

void Engine::RunBundleAndSource(const std::string& bundle_path,
                                const std::string& main,
                                const std::string& packages) {
  TRACE_EVENT0("flutter", "Engine::RunBundleAndSource");
  FTL_CHECK(!blink::IsRunningPrecompiledCode())
      << "Cannot run from source in a precompiled build.";
  std::string packages_path = packages;
  if (packages_path.empty())
    packages_path = FindPackagesPath(main);
  if (!bundle_path.empty())
    ConfigureAssetBundle(bundle_path);
  ConfigureRuntime(GetScriptUriFromPath(main));
  runtime_->dart_controller()->RunFromSource(main, packages_path);
}

A
Adam Barth 已提交
133
void Engine::BeginFrame(ftl::TimePoint frame_time) {
134
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
135 136
  if (runtime_)
    runtime_->BeginFrame(frame_time);
A
Adam Barth 已提交
137 138
}

139 140
void Engine::RunFromSource(const std::string& main,
                           const std::string& packages,
141 142
                           const std::string& bundle_path) {
  RunBundleAndSource(bundle_path, main, packages);
143 144
}

145
Dart_Port Engine::GetUIIsolateMainPort() {
146
  if (!runtime_)
147
    return ILLEGAL_PORT;
148
  return runtime_->GetMainPort();
149 150
}

151 152 153 154 155 156 157
std::string Engine::GetUIIsolateName() {
  if (!runtime_) {
    return "";
  }
  return runtime_->GetIsolateName();
}

158 159
void Engine::ConnectToEngine(mojo::InterfaceRequest<SkyEngine> request) {
  binding_.Bind(request.Pass());
160 161
}

162
void Engine::OnOutputSurfaceCreated(const ftl::Closure& gpu_continuation) {
163
  blink::Threads::Gpu()->PostTask(gpu_continuation);
164 165
  have_surface_ = true;
  StartAnimatorIfPossible();
166
  if (runtime_)
167
    ScheduleFrame();
168 169
}

170
void Engine::OnOutputSurfaceDestroyed(const ftl::Closure& gpu_continuation) {
171 172
  have_surface_ = false;
  StopAnimator();
173
  blink::Threads::Gpu()->PostTask(gpu_continuation);
174 175
}

176 177
void Engine::SetViewportMetrics(const blink::ViewportMetrics& metrics) {
  viewport_metrics_ = metrics;
178 179
  if (runtime_)
    runtime_->SetViewportMetrics(viewport_metrics_);
180 181
}

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
void Engine::DispatchPlatformMessage(
    ftl::RefPtr<blink::PlatformMessage> message) {
  if (message->channel() == kLifecycleChannel) {
    if (HandleLifecyclePlatformMessage(message.get()))
      return;
  } else if (message->channel() == kLocalizationChannel) {
    if (HandleLocalizationPlatformMessage(std::move(message)))
      return;
  }

  if (runtime_) {
    runtime_->DispatchPlatformMessage(std::move(message));
    return;
  }

  // If there's no runtime_, we need to buffer some navigation messages.
  if (message->channel() == kNavigationChannel)
    HandleNavigationPlatformMessage(std::move(message));
200 201
}

202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
bool Engine::HandleLifecyclePlatformMessage(blink::PlatformMessage* message) {
  const auto& data = message->data();
  std::string state(reinterpret_cast<const char*>(data.data()), data.size());
  if (state == "AppLifecycleState.paused") {
    activity_running_ = false;
    StopAnimator();
  } else if (state == "AppLifecycleState.resumed") {
    activity_running_ = true;
    StartAnimatorIfPossible();
  }
  return false;
}

bool Engine::HandleNavigationPlatformMessage(
    ftl::RefPtr<blink::PlatformMessage> message) {
  FTL_DCHECK(!runtime_);
  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 != "pushRoute")
    return false;

  pending_push_route_message_ = std::move(message);
  return true;
}

bool Engine::HandleLocalizationPlatformMessage(
A
Adam Barth 已提交
234
    ftl::RefPtr<blink::PlatformMessage> message) {
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
  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;

  const auto& language = args->value[0];
  const auto& country = args->value[1];

  if (!language.IsString() || !country.IsString())
    return false;

  language_code_ = language.GetString();
  country_code_ = country.GetString();
A
Adam Barth 已提交
258
  if (runtime_)
259 260
    runtime_->SetLocale(language_code_, country_code_);
  return true;
A
Adam Barth 已提交
261 262
}

263
void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet) {
264
  if (runtime_)
265
    runtime_->DispatchPointerDataPacket(packet);
266 267
}

268 269 270 271 272 273
void Engine::DispatchSemanticsAction(int id, blink::SemanticsAction action) {
  if (runtime_)
    runtime_->DispatchSemanticsAction(id, action);
}

void Engine::SetSemanticsEnabled(bool enabled) {
A
Adam Barth 已提交
274
  semantics_enabled_ = enabled;
275
  if (runtime_)
A
Adam Barth 已提交
276
    runtime_->SetSemanticsEnabled(semantics_enabled_);
277 278
}

279 280 281
void Engine::ConfigureAssetBundle(const std::string& path) {
  struct stat stat_result = {0};

A
Adam Barth 已提交
282 283 284
  directory_asset_bundle_.reset();
  zip_asset_bundle_.reset();

285 286 287 288
  if (::stat(path.c_str(), &stat_result) != 0) {
    LOG(INFO) << "Could not configure asset bundle at path: " << path;
    return;
  }
289

290 291
  if (S_ISDIR(stat_result.st_mode)) {
    // Directory asset bundle.
A
Adam Barth 已提交
292 293
    directory_asset_bundle_ = std::make_unique<blink::DirectoryAssetBundle>(
        mojo::GetProxy(&root_bundle_), path, blink::Threads::IO());
294 295 296 297 298
    return;
  }

  if (S_ISREG(stat_result.st_mode)) {
    // Zip asset bundle.
A
Adam Barth 已提交
299 300
    asset_store_ = ftl::MakeRefCounted<blink::ZipAssetStore>(
        blink::GetUnzipperProviderForPath(path), blink::Threads::IO());
A
Adam Barth 已提交
301 302
    zip_asset_bundle_ = std::make_unique<blink::ZipAssetBundle>(
        mojo::GetProxy(&root_bundle_), asset_store_);
303 304
    return;
  }
305 306
}

307
void Engine::ConfigureRuntime(const std::string& script_uri) {
308
  snapshot_drainer_.reset();
309 310 311 312
  runtime_ = blink::RuntimeController::Create(this);
  runtime_->CreateDartController(std::move(script_uri));
  runtime_->SetViewportMetrics(viewport_metrics_);
  runtime_->SetLocale(language_code_, country_code_);
A
Adam Barth 已提交
313
  runtime_->SetSemanticsEnabled(semantics_enabled_);
314 315
  if (pending_push_route_message_)
    runtime_->DispatchPlatformMessage(std::move(pending_push_route_message_));
316 317
}

318
void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
319
  RunBundle(bundle_path);
320 321
}

322
void Engine::RunFromFile(const mojo::String& main,
323
                         const mojo::String& packages,
324
                         const mojo::String& bundle) {
325
  RunBundleAndSource(bundle, main, packages);
326 327
}

328
void Engine::RunFromBundle(const mojo::String& script_uri,
329 330
                           const mojo::String& bundle_path) {
  RunBundle(bundle_path);
331 332
}

333 334
void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
                                      const mojo::String& bundle_path,
335
                                      const mojo::String& snapshot_path) {
336
  RunBundleAndSnapshot(bundle_path, snapshot_path);
337 338
}

339
void Engine::DidCreateMainIsolate(Dart_Isolate isolate) {
340
  if (asset_store_)
341
    blink::AssetFontSelector::Install(asset_store_);
342 343
}

344
void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {}
345

346 347 348 349 350 351 352 353 354
void Engine::StopAnimator() {
  animator_->Stop();
}

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

355
void Engine::ScheduleFrame() {
A
Adam Barth 已提交
356 357 358
  animator_->RequestFrame();
}

359 360 361
void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree)
    return;
362

363 364
  SkISize frame_size = SkISize::Make(viewport_metrics_.physical_width,
                                     viewport_metrics_.physical_height);
365 366 367 368
  if (frame_size.isEmpty())
    return;

  layer_tree->set_frame_size(frame_size);
369 370
  animator_->Render(std::move(layer_tree));
}
371

372 373 374 375 376 377 378
void Engine::UpdateSemantics(std::vector<blink::SemanticsNode> update) {
  blink::Threads::Platform()->PostTask(ftl::MakeCopyable(
      [ platform_view = platform_view_, update = std::move(update) ]() mutable {
        if (platform_view)
          platform_view->UpdateSemantics(std::move(update));
      }));
}
379

380 381
void Engine::HandlePlatformMessage(
    ftl::RefPtr<blink::PlatformMessage> message) {
382
  if (message->channel() == kAssetChannel) {
A
Adam Barth 已提交
383 384 385
    HandleAssetPlatformMessage(std::move(message));
    return;
  }
386 387 388 389 390 391 392 393
  blink::Threads::Platform()->PostTask([
    platform_view = platform_view_, message = std::move(message)
  ]() mutable {
    if (platform_view)
      platform_view->HandlePlatformMessage(std::move(message));
  });
}

A
Adam Barth 已提交
394 395 396 397 398 399 400 401 402
void Engine::HandleAssetPlatformMessage(
    ftl::RefPtr<blink::PlatformMessage> message) {
  ftl::RefPtr<blink::PlatformMessageResponse> response = message->response();
  if (!response)
    return;
  const auto& data = message->data();
  std::string asset_name(reinterpret_cast<const char*>(data.data()),
                         data.size());
  std::vector<uint8_t> asset_data;
403
  if (GetAssetAsBuffer(asset_name, &asset_data)) {
A
Adam Barth 已提交
404 405 406 407 408 409
    response->Complete(std::move(asset_data));
  } else {
    response->CompleteWithError();
  }
}

410 411 412 413 414 415 416
bool Engine::GetAssetAsBuffer(const std::string& name,
                              std::vector<uint8_t>* data) {
  return (directory_asset_bundle_ &&
          directory_asset_bundle_->GetAsBuffer(name, data)) ||
         (asset_store_ && asset_store_->GetAsBuffer(name, data));
}

417
}  // namespace shell