engine.cc 10.7 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/path.h"
25
#include "lib/ftl/functional/make_copyable.h"
26
#include "mojo/public/cpp/application/connect.h"
A
Adam Barth 已提交
27 28
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
29 30

namespace shell {
31
namespace {
32

A
Adam Barth 已提交
33 34
constexpr char kAssetPluginChannel[] = "flutter/assets";

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
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;
}

51 52
}  // namespace

53 54
Engine::Engine(PlatformView* platform_view)
    : platform_view_(platform_view->GetWeakPtr()),
55 56 57 58
      animator_(std::make_unique<Animator>(
          platform_view->rasterizer().GetWeakRasterizerPtr(),
          platform_view->GetVsyncWaiter(),
          this)),
59
      binding_(this),
60 61
      activity_running_(false),
      have_surface_(false),
62
      weak_factory_(this) {}
63

64
Engine::~Engine() {}
65

66
ftl::WeakPtr<Engine> Engine::GetWeakPtr() {
67 68 69
  return weak_factory_.GetWeakPtr();
}

70
void Engine::Init() {
71
  blink::InitRuntime();
72 73
}

A
Adam Barth 已提交
74
void Engine::BeginFrame(ftl::TimePoint frame_time) {
75
  TRACE_EVENT0("flutter", "Engine::BeginFrame");
76 77
  if (runtime_)
    runtime_->BeginFrame(frame_time);
A
Adam Barth 已提交
78 79
}

80 81
void Engine::RunFromSource(const std::string& main,
                           const std::string& packages,
82
                           const std::string& bundle) {
83
  TRACE_EVENT0("flutter", "Engine::RunFromSource");
84 85 86
  std::string packages_path = packages;
  if (packages_path.empty())
    packages_path = FindPackagesPath(main);
87
  if (!bundle.empty())
88
    ConfigureAssetBundle(bundle);
89 90
  ConfigureRuntime(main);
  runtime_->dart_controller()->RunFromSource(main, packages_path);
91 92
}

93
Dart_Port Engine::GetUIIsolateMainPort() {
94
  if (!runtime_)
95
    return ILLEGAL_PORT;
96
  return runtime_->GetMainPort();
97 98
}

99 100 101 102 103 104 105
std::string Engine::GetUIIsolateName() {
  if (!runtime_) {
    return "";
  }
  return runtime_->GetIsolateName();
}

106 107
void Engine::ConnectToEngine(mojo::InterfaceRequest<SkyEngine> request) {
  binding_.Bind(request.Pass());
108 109
}

110
void Engine::OnOutputSurfaceCreated(const ftl::Closure& gpu_continuation) {
111
  blink::Threads::Gpu()->PostTask(gpu_continuation);
112 113
  have_surface_ = true;
  StartAnimatorIfPossible();
114
  if (runtime_)
115
    ScheduleFrame();
116 117
}

118
void Engine::OnOutputSurfaceDestroyed(const ftl::Closure& gpu_continuation) {
119 120
  have_surface_ = false;
  StopAnimator();
121
  blink::Threads::Gpu()->PostTask(gpu_continuation);
122 123
}

124
void Engine::OnViewportMetricsChanged(sky::ViewportMetricsPtr metrics) {
125
  viewport_metrics_ = metrics.Pass();
126 127
  if (runtime_)
    runtime_->SetViewportMetrics(viewport_metrics_);
128 129
}

130
void Engine::OnLocaleChanged(const mojo::String& language_code,
131
                             const mojo::String& country_code) {
132 133
  language_code_ = language_code;
  country_code_ = country_code;
134 135
  if (runtime_)
    runtime_->SetLocale(language_code_, country_code_);
136 137
}

A
Adam Barth 已提交
138 139 140 141 142 143
void Engine::DispatchPlatformMessage(
    ftl::RefPtr<blink::PlatformMessage> message) {
  if (runtime_)
    runtime_->DispatchPlatformMessage(std::move(message));
}

144
void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet) {
145
  if (runtime_)
146
    runtime_->DispatchPointerDataPacket(packet);
147 148
}

149 150 151 152 153 154
void Engine::DispatchSemanticsAction(int id, blink::SemanticsAction action) {
  if (runtime_)
    runtime_->DispatchSemanticsAction(id, action);
}

void Engine::SetSemanticsEnabled(bool enabled) {
A
Adam Barth 已提交
155
  semantics_enabled_ = enabled;
156
  if (runtime_)
A
Adam Barth 已提交
157
    runtime_->SetSemanticsEnabled(semantics_enabled_);
158 159
}

160
void Engine::RunFromSnapshotStream(
161
    const std::string& script_uri,
162
    mojo::ScopedDataPipeConsumerHandle snapshot) {
163
  TRACE_EVENT0("flutter", "Engine::RunFromSnapshotStream");
164
  ConfigureRuntime(script_uri);
165
  snapshot_drainer_.reset(new glue::DrainDataPipeJob(
166
      std::move(snapshot), [this](std::vector<uint8_t> snapshot) {
167 168
        FTL_DCHECK(runtime_);
        FTL_DCHECK(runtime_->dart_controller());
169 170
        runtime_->dart_controller()->RunFromSnapshot(snapshot.data(),
                                                     snapshot.size());
171
      }));
172 173
}

174 175 176
void Engine::ConfigureAssetBundle(const std::string& path) {
  struct stat stat_result = {0};

A
Adam Barth 已提交
177 178 179
  directory_asset_bundle_.reset();
  zip_asset_bundle_.reset();

180 181 182 183
  if (::stat(path.c_str(), &stat_result) != 0) {
    LOG(INFO) << "Could not configure asset bundle at path: " << path;
    return;
  }
184

185 186
  if (S_ISDIR(stat_result.st_mode)) {
    // Directory asset bundle.
A
Adam Barth 已提交
187 188
    directory_asset_bundle_ = std::make_unique<blink::DirectoryAssetBundle>(
        mojo::GetProxy(&root_bundle_), path, blink::Threads::IO());
189 190 191 192 193
    return;
  }

  if (S_ISREG(stat_result.st_mode)) {
    // Zip asset bundle.
A
Adam Barth 已提交
194 195
    asset_store_ = ftl::MakeRefCounted<blink::ZipAssetStore>(
        blink::GetUnzipperProviderForPath(path), blink::Threads::IO());
A
Adam Barth 已提交
196 197
    zip_asset_bundle_ = std::make_unique<blink::ZipAssetBundle>(
        mojo::GetProxy(&root_bundle_), asset_store_);
198 199
    return;
  }
200 201
}

202
void Engine::ConfigureRuntime(const std::string& script_uri) {
203
  snapshot_drainer_.reset();
204 205 206 207
  runtime_ = blink::RuntimeController::Create(this);
  runtime_->CreateDartController(std::move(script_uri));
  runtime_->SetViewportMetrics(viewport_metrics_);
  runtime_->SetLocale(language_code_, country_code_);
A
Adam Barth 已提交
208
  runtime_->SetSemanticsEnabled(semantics_enabled_);
A
Adam Barth 已提交
209
  if (!initial_route_.empty())
210
    runtime_->PushRoute(initial_route_);
211 212
}

213 214
void Engine::RunFromPrecompiledSnapshot(const mojo::String& bundle_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromPrecompiledSnapshot");
215
  ConfigureAssetBundle(bundle_path.get());
216 217
  ConfigureRuntime("http://localhost");
  runtime_->dart_controller()->RunFromPrecompiledSnapshot();
218 219
}

220
void Engine::RunFromFile(const mojo::String& main,
221
                         const mojo::String& packages,
222
                         const mojo::String& bundle) {
223
  RunFromSource(main, packages, bundle);
224 225
}

226 227
void Engine::RunFromBundle(const mojo::String& script_uri,
                           const mojo::String& path) {
228
  TRACE_EVENT0("flutter", "Engine::RunFromBundle");
229
  ConfigureAssetBundle(path);
230 231 232 233
  mojo::DataPipe pipe;
  asset_store_->GetAsStream(blink::kSnapshotAssetKey,
                            std::move(pipe.producer_handle));
  RunFromSnapshotStream(script_uri, std::move(pipe.consumer_handle));
234 235
}

236 237
void Engine::RunFromBundleAndSnapshot(const mojo::String& script_uri,
                                      const mojo::String& bundle_path,
238 239
                                      const mojo::String& snapshot_path) {
  TRACE_EVENT0("flutter", "Engine::RunFromBundleAndSnapshot");
240

241
  ConfigureAssetBundle(bundle_path);
242

243
  asset_store_->AddOverlayFile(blink::kSnapshotAssetKey, snapshot_path);
244 245 246 247
  mojo::DataPipe pipe;
  asset_store_->GetAsStream(blink::kSnapshotAssetKey,
                            std::move(pipe.producer_handle));
  RunFromSnapshotStream(script_uri, std::move(pipe.consumer_handle));
248 249
}

A
Adam Barth 已提交
250
void Engine::PushRoute(const mojo::String& route) {
251 252
  if (runtime_)
    runtime_->PushRoute(route);
A
Adam Barth 已提交
253 254 255 256 257
  else
    initial_route_ = route;
}

void Engine::PopRoute() {
258 259
  if (runtime_)
    runtime_->PopRoute();
A
Adam Barth 已提交
260 261
}

262 263 264 265 266 267 268 269 270 271 272 273
void Engine::OnAppLifecycleStateChanged(sky::AppLifecycleState state) {
  switch (state) {
    case sky::AppLifecycleState::PAUSED:
      activity_running_ = false;
      StopAnimator();
      break;

    case sky::AppLifecycleState::RESUMED:
      activity_running_ = true;
      StartAnimatorIfPossible();
      break;
  }
274

275 276
  if (runtime_)
    runtime_->OnAppLifecycleStateChanged(state);
277 278
}

279
void Engine::DidCreateMainIsolate(Dart_Isolate isolate) {
280
  if (asset_store_)
281
    blink::AssetFontSelector::Install(asset_store_);
282 283
}

284
void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {}
285

286 287 288 289 290 291 292 293 294
void Engine::StopAnimator() {
  animator_->Stop();
}

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

295
void Engine::ScheduleFrame() {
A
Adam Barth 已提交
296 297 298
  animator_->RequestFrame();
}

299 300 301
void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree)
    return;
302 303 304
  if (!viewport_metrics_)
    return;

305 306
  SkISize frame_size = SkISize::Make(viewport_metrics_->physical_width,
                                     viewport_metrics_->physical_height);
307 308 309 310 311
  if (frame_size.isEmpty())
    return;

  layer_tree->set_scene_version(viewport_metrics_->scene_version);
  layer_tree->set_frame_size(frame_size);
312 313
  animator_->Render(std::move(layer_tree));
}
314

315 316 317 318 319 320 321
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));
      }));
}
322

323 324
void Engine::HandlePlatformMessage(
    ftl::RefPtr<blink::PlatformMessage> message) {
325
  if (message->channel() == kAssetPluginChannel) {
A
Adam Barth 已提交
326 327 328
    HandleAssetPlatformMessage(std::move(message));
    return;
  }
329 330 331 332 333 334 335 336
  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 已提交
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
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;
  if ((directory_asset_bundle_ &&
       directory_asset_bundle_->GetAsBuffer(asset_name, &asset_data)) ||
      (asset_store_ && asset_store_->GetAsBuffer(asset_name, &asset_data))) {
    response->Complete(std::move(asset_data));
  } else {
    response->CompleteWithError();
  }
}

355
}  // namespace shell