Skip to content

Commit

Permalink
Implement RunInView service protocol extension (flutter#2862)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnmccutchan authored Aug 4, 2016
1 parent 603b070 commit b13b79b
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 26 deletions.
4 changes: 2 additions & 2 deletions DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ vars = {

# Note: When updating the Dart revision, ensure that all entries that are
# dependencies of dart are also updated
'dart_revision': '39ae4337dd8b6b1a66e7b7dc5142efffef3dd6ed',
'dart_revision': 'aed6dd844d3f49acf97294e45d0ec9cfeaf6f508',
'dart_boringssl_revision': 'daeafc22c66ad48f6b32fc8d3362eb9ba31b774e',
'dart_observatory_packages_revision': 'e5e1e543bea10d4bed95b22ad3e7aa2b20a23584',
'dart_observatory_packages_revision': 'a01235b5b71df27b602dae4676d0bf771cbe7fa2',
'dart_root_certificates_revision': 'aed07942ce98507d2be28cbd29e879525410c7fc',

'buildtools_revision': '565d04e8741429fb1b4f26d102f2c6c3b849edeb',
Expand Down
6 changes: 5 additions & 1 deletion flutter/tonic/dart_message_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ void DartMessageHandler::OnHandleMessage(DartState* dart_state) {

void DartMessageHandler::MessageNotifyCallback(Dart_Isolate dest_isolate) {
auto dart_state = DartState::From(dest_isolate);
FTL_CHECK(dart_state);
if (!dart_state) {
// The callback data for an isolate can be null if the isolate is in the
// middle of being shutdown.
return;
}
dart_state->message_handler().OnMessage(dart_state);
}

Expand Down
2 changes: 2 additions & 0 deletions sky/engine/core/script/dart_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ DartController::~DartController() {
if (ui_dart_state_) {
// Don't use a tonic::DartIsolateScope here since we never exit the isolate.
Dart_EnterIsolate(ui_dart_state_->isolate());
// Clear the message notify callback.
Dart_SetMessageNotifyCallback(nullptr);
Dart_ShutdownIsolate(); // deletes ui_dart_state_
ui_dart_state_ = nullptr;
}
Expand Down
3 changes: 1 addition & 2 deletions sky/engine/core/script/dart_init.cc
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,7 @@ bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) {
since_ms - (since_seconds * base::Time::kMillisecondsPerSecond);
base::Time since_time = base::Time::FromTimeT(since_seconds) +
base::TimeDelta::FromMilliseconds(since_milliseconds);
// TODO(johnmccutchan): Remove 'true ||' after Todd's fix has landed.
return true || file_info.last_modified > since_time;
return file_info.last_modified > since_time;
}

void ThreadExitCallback() {
Expand Down
5 changes: 5 additions & 0 deletions sky/engine/core/script/directory_asset_bundle.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SKY_ENGINE_CORE_SCRIPT_DIRECTORY_ASSET_BUNDLE_H_
#define SKY_ENGINE_CORE_SCRIPT_DIRECTORY_ASSET_BUNDLE_H_

#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/interface_request.h"
Expand Down Expand Up @@ -35,3 +38,5 @@ class DirectoryAssetBundleService : public mojo::asset_bundle::AssetBundle {
};

} // namespace blink

#endif // SKY_ENGINE_CORE_SCRIPT_DIRECTORY_ASSET_BUNDLE_H_
4 changes: 4 additions & 0 deletions sky/shell/platform_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class PlatformView {

virtual void Resize(const SkISize& size);

Engine& engine() {
return *engine_;
}

protected:
Config config_;
SurfaceConfig surface_config_;
Expand Down
128 changes: 120 additions & 8 deletions sky/shell/platform_view_service_protocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,79 @@

#include "sky/shell/platform_view_service_protocol.h"

#include <string>

#include "base/strings/string_util.h"
#include "sky/shell/shell.h"

namespace sky {
namespace shell {

namespace {

static intptr_t KeyIndex(const char** param_keys,
intptr_t num_params,
const char* key) {
if (param_keys == NULL) {
return -1;
}
for (intptr_t i = 0; i < num_params; i++) {
if (strcmp(param_keys[i], key) == 0) {
return i;
}
}
return -1;
}

static const char* ValueForKey(const char** param_keys,
const char** param_values,
intptr_t num_params,
const char* key) {
intptr_t index = KeyIndex(param_keys, num_params, key);
if (index < 0) {
return NULL;
}
return param_values[index];
}

static bool ErrorMissingParameter(const char** json_object,
const char* name) {
const intptr_t kInvalidParams = -32602;
std::stringstream response;
response << "{\"code\":" << std::to_string(kInvalidParams) << ",";
response << "\"message\":\"Invalid params\",";
response << "\"data\": {\"details\": \"" << name << "\"}}";
*json_object = strdup(response.str().c_str());
return false;
}

static bool ErrorBadParameter(const char** json_object,
const char* name,
const char* value) {
const intptr_t kInvalidParams = -32602;
std::stringstream response;
response << "{\"code\":" << std::to_string(kInvalidParams) << ",";
response << "\"message\":\"Invalid params\",";
response << "\"data\": {\"details\": \"parameter: " << name << " has a bad ";
response << "value: " << value << "\"}}";
*json_object = strdup(response.str().c_str());
return false;
}

static bool ErrorUnknownView(const char** json_object,
const char* view_id) {
const intptr_t kInvalidParams = -32602;
std::stringstream response;
response << "{\"code\":" << std::to_string(kInvalidParams) << ",";
response << "\"message\":\"Invalid params\",";
response << "\"data\": {\"details\": \"view not found: " << view_id << "\"}}";
*json_object = strdup(response.str().c_str());
return false;
}

} // namespace


void PlatformViewServiceProtocol::RegisterHook(bool running_precompiled_code) {
if (running_precompiled_code) {
return;
Expand All @@ -30,8 +98,53 @@ bool PlatformViewServiceProtocol::RunInView(const char* method,
intptr_t num_params,
void* user_data,
const char** json_object) {
// TODO(johnmccutchan): Implement this.
*json_object = strdup("{\"type\": \"Success\"}");
const char* view_id =
ValueForKey(param_keys, param_values, num_params, "viewId");
const char* asset_directory =
ValueForKey(param_keys, param_values, num_params, "assetDirectory");
const char* main_script =
ValueForKey(param_keys, param_values, num_params, "mainScript");
const char* packages_file =
ValueForKey(param_keys, param_values, num_params, "packagesFile");
if (view_id == NULL) {
return ErrorMissingParameter(json_object, "viewId");
}
if (!base::StartsWithASCII(view_id, "_flutterView/", true)) {
return ErrorBadParameter(json_object, "viewId", view_id);
}
if (asset_directory == NULL) {
return ErrorMissingParameter(json_object, "assetDirectory");
}
if (main_script == NULL) {
return ErrorMissingParameter(json_object, "mainScript");
}
if (packages_file == NULL) {
return ErrorMissingParameter(json_object, "packagesFile");
}

// Convert the actual flutter view hex id into a number.
uintptr_t view_id_as_num =
std::stoull((view_id + strlen("_flutterView/")), nullptr, 16);

// Ask the Shell to run this script in the specified view. This will run a
// task on the UI thread before returning.
Shell& shell = Shell::Shared();
bool view_existed = false;
shell.RunInPlatformView(view_id_as_num,
main_script,
packages_file,
asset_directory,
&view_existed);

if (!view_existed) {
// If the view did not exist this request has definitely failed.
return ErrorUnknownView(json_object, view_id);
} else {
// The view existed and the run was requested. Success.
// TODO(johnmccutchan): Can we send back any launch errors here?
*json_object = strdup("{\"type\": \"Success\"}");
return true;
}
return true;
}

Expand All @@ -47,17 +160,16 @@ bool PlatformViewServiceProtocol::ListViews(const char* method,
// Ask the Shell for the list of platform views. This will run a task on
// the UI thread before returning.
Shell& shell = Shell::Shared();
std::vector<base::WeakPtr<PlatformView>> platform_views;
shell.WaitForPlatformViews(&platform_views);
std::vector<uintptr_t> platform_views;
shell.WaitForPlatformViewIds(&platform_views);

std::stringstream response;

response << "{\"type\":\"FlutterViewList\",\"views\":[";
bool prefix_comma = false;
for (auto it = platform_views.begin(); it != platform_views.end(); it++) {
PlatformView* view = it->get();
if (!view) {
// Skip any platform views which have been deleted.
uintptr_t view_id = *it;
if (!view_id) {
continue;
}
if (prefix_comma) {
Expand All @@ -66,7 +178,7 @@ bool PlatformViewServiceProtocol::ListViews(const char* method,
prefix_comma = true;
}
response << "{\"type\":\"FlutterView\", \"id\": \"_flutterView/";
response << "0x" << std::hex << reinterpret_cast<uintptr_t>(view);
response << "0x" << std::hex << view_id;
response << "\"}";
}
response << "]}";
Expand Down
73 changes: 64 additions & 9 deletions sky/shell/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,10 @@ void Shell::InitGpuThread() {
gpu_thread_checker_.reset(new base::ThreadChecker());
}


void Shell::InitUIThread() {
ui_thread_checker_.reset(new base::ThreadChecker());
}


void Shell::AddRasterizer(const base::WeakPtr<Rasterizer>& rasterizer) {
DCHECK(gpu_thread_checker_ && gpu_thread_checker_->CalledOnValidThread());
rasterizers_.push_back(rasterizer);
Expand Down Expand Up @@ -227,25 +225,82 @@ void Shell::GetPlatformViews(
*platform_views = platform_views_;
}

void Shell::WaitForPlatformViews(
std::vector<base::WeakPtr<PlatformView>>* platform_views) {
void Shell::WaitForPlatformViewIds(
std::vector<uintptr_t>* platform_view_ids) {

base::WaitableEvent latch(false, false);

ui_task_runner()->PostTask(
FROM_HERE,
base::Bind(&Shell::WaitForPlatformViewsUIThread,
base::Bind(&Shell::WaitForPlatformViewsIdsUIThread,
base::Unretained(this),
base::Unretained(platform_views),
base::Unretained(platform_view_ids),
base::Unretained(&latch)));

latch.Wait();
}

void Shell::WaitForPlatformViewsUIThread(
std::vector<base::WeakPtr<PlatformView>>* platform_views,
void Shell::WaitForPlatformViewsIdsUIThread(
std::vector<uintptr_t>* platform_view_ids,
base::WaitableEvent* latch) {
GetPlatformViews(platform_views);
std::vector<base::WeakPtr<PlatformView>> platform_views;
GetPlatformViews(&platform_views);
for (auto it = platform_views.begin(); it != platform_views.end(); it++) {
PlatformView* view = it->get();
if (!view) {
// Skip dead views.
continue;
}
platform_view_ids->push_back(reinterpret_cast<uintptr_t>(view));
}
latch->Signal();
}

void Shell::RunInPlatformView(uintptr_t view_id,
const char* main_script,
const char* packages_file,
const char* asset_directory,
bool* view_existed) {
base::WaitableEvent latch(false, false);
DCHECK(view_id != 0);
DCHECK(main_script);
DCHECK(packages_file);
DCHECK(asset_directory);
DCHECK(view_existed);

ui_task_runner()->PostTask(
FROM_HERE,
base::Bind(&Shell::RunInPlatformViewUIThread,
base::Unretained(this),
view_id,
std::string(main_script),
std::string(packages_file),
std::string(asset_directory),
base::Unretained(view_existed),
base::Unretained(&latch)));

latch.Wait();
}

void Shell::RunInPlatformViewUIThread(uintptr_t view_id,
const std::string& main,
const std::string& packages,
const std::string& assets_directory,
bool* view_existed,
base::WaitableEvent* latch) {
DCHECK(ui_thread_checker_ && ui_thread_checker_->CalledOnValidThread());

*view_existed = false;

for (auto it = platform_views_.begin(); it != platform_views_.end(); it++) {
PlatformView* view = it->get();
if (reinterpret_cast<uintptr_t>(view) == view_id) {
*view_existed = true;
view->engine().RunFromSource(main, packages, assets_directory);
break;
}
}

latch->Signal();
}

Expand Down
23 changes: 19 additions & 4 deletions sky/shell/shell.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,34 @@ class Shell {
platform_views);

// These APIs can be called from any thread.
void WaitForPlatformViews(
std::vector<base::WeakPtr<PlatformView>>* platform_views);
// Return the list of platform view ids at the time of this call.
void WaitForPlatformViewIds(
std::vector<uintptr_t>* platform_view_ids);
// Attempt to run a script inside a flutter view indicated by |view_id|.
// Will set |view_existed| to true if the view was found and false otherwise.
void RunInPlatformView(uintptr_t view_id,
const char* main_script,
const char* packages_file,
const char* asset_directory,
bool* view_existed);

private:
Shell();

void InitGpuThread();
void InitUIThread();

void WaitForPlatformViewsUIThread(
std::vector<base::WeakPtr<PlatformView>>* platform_views,
void WaitForPlatformViewsIdsUIThread(
std::vector<uintptr_t>* platform_views,
base::WaitableEvent* latch);

void RunInPlatformViewUIThread(uintptr_t view_id,
const std::string& main,
const std::string& packages,
const std::string& assets_directory,
bool* view_existed,
base::WaitableEvent* latch);

std::unique_ptr<base::Thread> gpu_thread_;
std::unique_ptr<base::Thread> ui_thread_;
std::unique_ptr<base::Thread> io_thread_;
Expand Down
Loading

0 comments on commit b13b79b

Please sign in to comment.