Reland "[fuchsia] Migrate web_engine_shell to launch web_instance.cm"
This is a reland of commit 986da2599c
with the following differences:
- web_engine_shell.cmx has been removed, as the use of v2 APIs to launch
web_instance.cm renders it inoperable.
- Documentation has been updated to illustrate how to run
web_engine_shell.cm.
- Application of the deprecated-allowed-packages test facet has been
fixed.
- fuchsia.tracing.provider.Registry is now routed dynamically by
WebInstanceHost conditionally based on the VULKAN ContextFeatureFlag.
Original change's description:
> [fuchsia] Migrate web_engine_shell to launch web_instance.cm
>
> In so doing:
>
> - A relauncher is introduced to launch a new component between
> test_manager and web_engine_shell when WebInstanceHost is used, as
> this is required for it to route capabilities to WebEngine.
> - WebInstanceHost now supports the test-only --with-webui switch to run
> a WebEngine with access to WebUI resources.
> - WebInstanceHost now destroys any active children upon destruction
> rather than requiring that the consumer wait for them to exit.
>
> Bug: 1280703
> Change-Id: I8481b854542524f7eef69d66059ff1767ba60f93
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4134846
> Reviewed-by: Wez <wez@chromium.org>
> Auto-Submit: Greg Thompson <grt@chromium.org>
> Commit-Queue: Greg Thompson <grt@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1095363}
Bug: 1280703
Change-Id: Ic29f67e3876ab2304bc515af85b742b7a596994f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4200488
Reviewed-by: David Dorwin <ddorwin@chromium.org>
Reviewed-by: Wez <wez@chromium.org>
Commit-Queue: Greg Thompson <grt@chromium.org>
Auto-Submit: Greg Thompson <grt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1104206}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
b682e914e2
commit
78920be75f
fuchsia_web
common
shell
BUILD.gnREADME.mdweb_engine_shell.ccweb_engine_shell.cmlweb_engine_shell.cmxweb_engine_shell_for_web_instance_host.cml
webengine
webinstance_host
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "base/check.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/ranges/algorithm.h"
|
||||
|
||||
using ::component_testing::ChildRef;
|
||||
using ::component_testing::Directory;
|
||||
@@ -22,24 +23,61 @@ using ::component_testing::Route;
|
||||
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
|
||||
void AppendCommandLineArgumentsToProgram(
|
||||
fuchsia::component::decl::Program& program,
|
||||
const base::CommandLine& command_line) {
|
||||
// Find the "args" list in the program declaration.
|
||||
fuchsia::data::DictionaryEntry* args_entry = nullptr;
|
||||
auto* entries = program.mutable_info()->mutable_entries();
|
||||
for (auto& entry : *entries) {
|
||||
if (entry.key == "args") {
|
||||
DCHECK(entry.value->is_str_vec());
|
||||
args_entry = &entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!args_entry) {
|
||||
// Create a new "args" list and insert it at the proper location in the
|
||||
// program's entries; entries' keys must be sorted as per
|
||||
// https://fuchsia.dev/reference/fidl/fuchsia.data?hl=en#Dictionary.
|
||||
auto lower_bound = base::ranges::lower_bound(
|
||||
*entries, "args", /*comp=*/{},
|
||||
[](const fuchsia::data::DictionaryEntry& entry) { return entry.key; });
|
||||
auto it = entries->emplace(lower_bound);
|
||||
it->key = "args";
|
||||
it->value = fuchsia::data::DictionaryValue::New();
|
||||
it->value->set_str_vec({});
|
||||
args_entry = &*it;
|
||||
}
|
||||
|
||||
// Append all args following the program name in `command_line` to the
|
||||
// program's args.
|
||||
args_entry->value->str_vec().insert(args_entry->value->str_vec().end(),
|
||||
command_line.argv().begin() + 1,
|
||||
command_line.argv().end());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AppendCommandLineArguments(RealmBuilder& realm_builder,
|
||||
base::StringPiece child_name,
|
||||
const base::CommandLine& command_line) {
|
||||
const std::string child_name_str(child_name);
|
||||
auto context_provider_decl = realm_builder.GetComponentDecl(child_name_str);
|
||||
for (auto& entry : *context_provider_decl.mutable_program()
|
||||
->mutable_info()
|
||||
->mutable_entries()) {
|
||||
if (entry.key == "args") {
|
||||
DCHECK(entry.value->is_str_vec());
|
||||
entry.value->str_vec().insert(entry.value->str_vec().end(),
|
||||
command_line.argv().begin() + 1,
|
||||
command_line.argv().end());
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto child_component_decl = realm_builder.GetComponentDecl(child_name_str);
|
||||
AppendCommandLineArgumentsToProgram(*child_component_decl.mutable_program(),
|
||||
command_line);
|
||||
realm_builder.ReplaceComponentDecl(child_name_str,
|
||||
std::move(context_provider_decl));
|
||||
std::move(child_component_decl));
|
||||
}
|
||||
|
||||
void AppendCommandLineArgumentsForRealm(
|
||||
::component_testing::RealmBuilder& realm_builder,
|
||||
const base::CommandLine& command_line) {
|
||||
auto decl = realm_builder.GetRealmDecl();
|
||||
AppendCommandLineArgumentsToProgram(*decl.mutable_program(), command_line);
|
||||
realm_builder.ReplaceRealmDecl(std::move(decl));
|
||||
}
|
||||
|
||||
void AddSyslogRoutesFromParent(RealmBuilder& realm_builder,
|
||||
|
@@ -24,6 +24,12 @@ void AppendCommandLineArguments(
|
||||
base::StringPiece child_name,
|
||||
const base::CommandLine& command_line);
|
||||
|
||||
// Appends the arguments of `command_line` (ignoring the program name at
|
||||
// position zero) to the command line for the realm.
|
||||
void AppendCommandLineArgumentsForRealm(
|
||||
::component_testing::RealmBuilder& realm_builder,
|
||||
const base::CommandLine& command_line);
|
||||
|
||||
// In the functions below, the term "parent" is the `#realm_builder` collection
|
||||
// for the test component that is using these helpers to build a test realm.
|
||||
// Each test component must use a .cml fragment that routes the required
|
||||
|
@@ -39,9 +39,13 @@ fuchsia_component("web_engine_shell_component") {
|
||||
data_deps = [ ":web_engine_shell_exec" ]
|
||||
}
|
||||
|
||||
fuchsia_component("web_engine_shell_component_v1") {
|
||||
# WebInstanceHost needs to serve capabilities to web_instance. Since the
|
||||
# primary web_engine_shell component is a test component, it is not able to do
|
||||
# this directly. Instead, it launches this here component to start instances via
|
||||
# WebInstanceHost.
|
||||
fuchsia_component("web_engine_shell_for_web_instance_host_component") {
|
||||
testonly = true
|
||||
manifest = "web_engine_shell.cmx"
|
||||
manifest = "web_engine_shell_for_web_instance_host.cml"
|
||||
data_deps = [ ":web_engine_shell_exec" ]
|
||||
}
|
||||
|
||||
@@ -52,7 +56,7 @@ fuchsia_package("web_engine_shell_pkg") {
|
||||
package_name = "web_engine_shell"
|
||||
deps = [
|
||||
":web_engine_shell_component",
|
||||
":web_engine_shell_component_v1",
|
||||
":web_engine_shell_for_web_instance_host_component",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -82,11 +86,15 @@ executable("web_engine_shell_exec") {
|
||||
":remote_debugging_port",
|
||||
"//base",
|
||||
"//fuchsia_web/common",
|
||||
"//fuchsia_web/webinstance_host:webinstance_host_v1",
|
||||
"//fuchsia_web/common/test:test_support",
|
||||
"//fuchsia_web/webinstance_host:webinstance_host",
|
||||
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.component:fuchsia.component_hlcpp",
|
||||
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.ui.policy:fuchsia.ui.policy_hlcpp",
|
||||
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.web:fuchsia.web_hlcpp",
|
||||
"//third_party/fuchsia-sdk/sdk/pkg/fdio",
|
||||
"//third_party/fuchsia-sdk/sdk/pkg/fidl_cpp",
|
||||
"//third_party/fuchsia-sdk/sdk/pkg/scenic_cpp",
|
||||
"//third_party/fuchsia-sdk/sdk/pkg/sys_component_cpp_testing",
|
||||
"//third_party/fuchsia-sdk/sdk/pkg/sys_cpp",
|
||||
"//third_party/widevine/cdm:buildflags",
|
||||
"//url",
|
||||
|
@@ -12,8 +12,7 @@ To build and run WebEngine Shell, execute the following commands:
|
||||
$ autoninja -C $OUTDIR web_engine_shell
|
||||
$ $OUTDIR/bin/deploy_web_engine_shell --fuchsia-out-dir $FUCHSIA_OUTDIR
|
||||
$ cd $FUCHSIA
|
||||
$ fx shell
|
||||
$ run fuchsia-pkg://fuchsia.com/web_engine_shell#meta/web_engine_shell.cmx --remote-debugging-port=1234 http://www.example.com
|
||||
$ ffx test run fuchsia-pkg://fuchsia.com/web_engine_shell#meta/web_engine_shell.cm -- --remote-debugging-port=1234 http://www.example.com
|
||||
```
|
||||
|
||||
Local files can be deployed with the WebEngine Shell and accessed via the
|
||||
@@ -22,5 +21,5 @@ by placing them under the path `//fuchsia_web/webengine/data`.
|
||||
|
||||
Here is an example command line which loads a local file:
|
||||
```
|
||||
$ run fuchsia-pkg://fuchsia.com/web_engine_shell#meta/web_engine_shell.cmx fuchsia-dir://data/index.html
|
||||
$ ffx test run fuchsia-pkg://fuchsia.com/web_engine_shell#meta/web_engine_shell.cm -- fuchsia-dir://data/index.html
|
||||
```
|
||||
|
@@ -2,16 +2,21 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <fuchsia/component/cpp/fidl.h>
|
||||
#include <fuchsia/ui/policy/cpp/fidl.h>
|
||||
#include <fuchsia/web/cpp/fidl.h>
|
||||
#include <lib/fdio/directory.h>
|
||||
#include <lib/fidl/cpp/interface_ptr.h>
|
||||
#include <lib/sys/component/cpp/testing/realm_builder.h>
|
||||
#include <lib/sys/cpp/component_context.h>
|
||||
#include <lib/sys/cpp/service_directory.h>
|
||||
#include <lib/ui/scenic/cpp/view_token_pair.h>
|
||||
#include <lib/vfs/cpp/pseudo_file.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include "base/base_paths.h"
|
||||
#include "base/check.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/fuchsia/file_utils.h"
|
||||
@@ -27,9 +32,10 @@
|
||||
#include "base/values.h"
|
||||
#include "build/build_config.h"
|
||||
#include "fuchsia_web/common/init_logging.h"
|
||||
#include "fuchsia_web/common/test/test_realm_support.h"
|
||||
#include "fuchsia_web/shell/remote_debugging_port.h"
|
||||
#include "fuchsia_web/webinstance_host/web_instance_host.h"
|
||||
#include "fuchsia_web/webinstance_host/web_instance_host_constants.h"
|
||||
#include "fuchsia_web/webinstance_host/web_instance_host_v1.h"
|
||||
#include "third_party/widevine/cdm/buildflags.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
@@ -38,6 +44,9 @@ namespace {
|
||||
constexpr char kHeadlessSwitch[] = "headless";
|
||||
constexpr char kEnableProtectedMediaIdentifier[] =
|
||||
"enable-protected-media-identifier";
|
||||
// Included on the command line when the shell is relaunched for use of
|
||||
// WebInstanceHost; see web_engine_shell_for_web_instance_host.cml.
|
||||
constexpr char kFromLauncher[] = "from-launcher";
|
||||
constexpr char kUseWebInstance[] = "use-web-instance";
|
||||
constexpr char kEnableWebInstanceTmp[] = "enable-web-instance-tmp";
|
||||
|
||||
@@ -69,17 +78,51 @@ GURL GetUrlFromArgs(const base::CommandLine::StringVector& args) {
|
||||
return url;
|
||||
}
|
||||
|
||||
// web_engine_shell needs to provide capabilities to children it launches (via
|
||||
// WebInstanceHost, for example). Test components are not able to do this, so
|
||||
// use RealmBuilder to relaunch web_engine_shell via
|
||||
// `web_engine_shell_for_web_instance_host_component` (which includes
|
||||
// `--from-launcher` on its command line) with the contents of this process's
|
||||
// command line.
|
||||
int RelaunchForWebInstanceHost(const base::CommandLine& command_line) {
|
||||
auto realm_builder = component_testing::RealmBuilder::CreateFromRelativeUrl(
|
||||
"#meta/web_engine_shell_for_web_instance_host.cm");
|
||||
test::AppendCommandLineArgumentsForRealm(realm_builder, // IN-TEST
|
||||
command_line);
|
||||
|
||||
auto realm = realm_builder.Build();
|
||||
|
||||
fuchsia::component::BinderPtr binder_proxy =
|
||||
realm.component().Connect<fuchsia::component::Binder>();
|
||||
|
||||
// Wait for binder_proxy to be closed.
|
||||
base::RunLoop run_loop;
|
||||
binder_proxy.set_error_handler(
|
||||
[quit_closure = run_loop.QuitClosure()](zx_status_t status) {
|
||||
std::move(quit_closure).Run();
|
||||
});
|
||||
run_loop.Run();
|
||||
|
||||
// Nothing depends on the process exit code of web_engine_shell today, so
|
||||
// simply return success in all cases.
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
base::CommandLine::Init(argc, argv);
|
||||
|
||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||
CHECK(InitLoggingFromCommandLine(*command_line));
|
||||
|
||||
base::SingleThreadTaskExecutor executor(base::MessagePumpType::IO);
|
||||
|
||||
// Parse the command line arguments and set up logging.
|
||||
CHECK(base::CommandLine::Init(argc, argv));
|
||||
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
|
||||
|
||||
CHECK(InitLoggingFromCommandLineDefaultingToStderrForTest( // IN-TEST
|
||||
command_line));
|
||||
const bool is_run_from_launcher = command_line->HasSwitch(kFromLauncher);
|
||||
const bool use_context_provider = !command_line->HasSwitch(kUseWebInstance);
|
||||
if (!is_run_from_launcher && !use_context_provider) {
|
||||
return RelaunchForWebInstanceHost(*command_line);
|
||||
}
|
||||
|
||||
absl::optional<uint16_t> remote_debugging_port =
|
||||
GetRemoteDebuggingPort(*command_line);
|
||||
@@ -91,7 +134,6 @@ int main(int argc, char** argv) {
|
||||
const bool is_headless = command_line->HasSwitch(kHeadlessSwitch);
|
||||
const bool enable_protected_media_identifier_access =
|
||||
command_line->HasSwitch(kEnableProtectedMediaIdentifier);
|
||||
const bool use_context_provider = !command_line->HasSwitch(kUseWebInstance);
|
||||
const bool enable_web_instance_tmp =
|
||||
command_line->HasSwitch(kEnableWebInstanceTmp);
|
||||
const bool with_webui = command_line->HasSwitch(switches::kWithWebui);
|
||||
@@ -173,12 +215,9 @@ int main(int argc, char** argv) {
|
||||
|
||||
base::RunLoop run_loop;
|
||||
|
||||
// Create the browser |context|.
|
||||
fuchsia::web::ContextPtr context;
|
||||
|
||||
// Keep alive in run_loop scope.
|
||||
fuchsia::web::ContextProviderPtr web_context_provider;
|
||||
std::unique_ptr<WebInstanceHostV1> web_instance_host;
|
||||
std::unique_ptr<WebInstanceHost> web_instance_host;
|
||||
fuchsia::web::ContextPtr context;
|
||||
fuchsia::io::DirectoryHandle tmp_directory;
|
||||
|
||||
if (use_context_provider) {
|
||||
@@ -189,7 +228,7 @@ int main(int argc, char** argv) {
|
||||
web_context_provider->Create(std::move(create_context_params),
|
||||
context.NewRequest());
|
||||
} else {
|
||||
web_instance_host = std::make_unique<WebInstanceHostV1>();
|
||||
web_instance_host = std::make_unique<WebInstanceHost>();
|
||||
if (enable_web_instance_tmp) {
|
||||
const zx_status_t status = fdio_open(
|
||||
"/tmp",
|
||||
@@ -290,6 +329,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
LOG(INFO) << "Launched browser at URL " << url.spec();
|
||||
|
||||
base::ComponentContextForProcess()->outgoing()->ServeFromStartupInfo();
|
||||
|
||||
// Run until the process is killed with CTRL-C or the connections to Web
|
||||
// Engine interfaces are dropped.
|
||||
run_loop.Run();
|
||||
|
@@ -10,38 +10,36 @@
|
||||
// to function correctly.
|
||||
"//build/config/fuchsia/test/chromium_test_facet.shard.test-cml",
|
||||
"//build/config/fuchsia/test/elf_test_ambient_exec_runner.shard.test-cml",
|
||||
"sys/component/realm_builder_absolute.shard.cml",
|
||||
"syslog/client.shard.cml",
|
||||
],
|
||||
program: {
|
||||
binary: "web_engine_shell_exec",
|
||||
},
|
||||
use: [
|
||||
{
|
||||
protocol: [
|
||||
"fuchsia.feedback.ComponentDataRegister",
|
||||
"fuchsia.feedback.CrashReportingProductRegister",
|
||||
"fuchsia.sys.Environment",
|
||||
"fuchsia.sys.Launcher",
|
||||
"fuchsia.sys.Loader",
|
||||
],
|
||||
},
|
||||
|
||||
// Used conditionally based on the absence of `--use-web-instance` on the
|
||||
// command line at runtime.
|
||||
{
|
||||
protocol: "fuchsia.web.ContextProvider",
|
||||
availability: "optional",
|
||||
},
|
||||
|
||||
// Used to hold the cdm_data directory passed to web_instance.
|
||||
{
|
||||
storage: "data",
|
||||
path: "/data",
|
||||
},
|
||||
|
||||
// Needed when launched with --enable-web-instance-tmp.
|
||||
{
|
||||
storage: "tmp",
|
||||
path: "/tmp",
|
||||
availability: "optional",
|
||||
},
|
||||
|
||||
// Uses below this line are for web_instance.cmx
|
||||
// Uses below this line are for web_instance.cmx.
|
||||
// TODO(crbug.com/1280703): Revise as needed when context_provider is
|
||||
// migrated to launch web_instance.cm.
|
||||
{
|
||||
protocol: [
|
||||
"fuchsia.buildinfo.Provider",
|
||||
@@ -93,10 +91,103 @@
|
||||
availability: "optional",
|
||||
},
|
||||
],
|
||||
offer: [
|
||||
{
|
||||
storage: [
|
||||
"data",
|
||||
"tmp",
|
||||
],
|
||||
from: "parent",
|
||||
to: "#realm_builder",
|
||||
},
|
||||
{
|
||||
directory: "root-ssl-certificates",
|
||||
from: "parent",
|
||||
to: "#realm_builder",
|
||||
},
|
||||
|
||||
// Offers for web_instance.cm.
|
||||
// The chromium test realm offers the system-wide config-data dir to test
|
||||
// components. Route the web_engine sub-directory of this as required by
|
||||
// WebInstanceHost.
|
||||
{
|
||||
directory: "config-data",
|
||||
from: "parent",
|
||||
as: "config-data-for-web-instance",
|
||||
to: "#realm_builder",
|
||||
subdir: "web_engine",
|
||||
availability: "optional",
|
||||
},
|
||||
{
|
||||
protocol: [
|
||||
"fuchsia.buildinfo.Provider",
|
||||
"fuchsia.device.NameProvider",
|
||||
"fuchsia.feedback.ComponentDataRegister",
|
||||
"fuchsia.feedback.CrashReportingProductRegister",
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.hwinfo.Product",
|
||||
"fuchsia.input.virtualkeyboard.ControllerCreator",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.kernel.VmexResource",
|
||||
"fuchsia.media.Audio",
|
||||
"fuchsia.media.AudioDeviceEnumerator",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.media.SessionAudioConsumerFactory",
|
||||
"fuchsia.mediacodec.CodecFactory",
|
||||
"fuchsia.memorypressure.Provider",
|
||||
"fuchsia.net.interfaces.State",
|
||||
"fuchsia.net.name.Lookup",
|
||||
"fuchsia.posix.socket.Provider",
|
||||
"fuchsia.process.Launcher",
|
||||
"fuchsia.sysmem.Allocator",
|
||||
"fuchsia.ui.input3.Keyboard",
|
||||
],
|
||||
from: "parent",
|
||||
to: "#realm_builder",
|
||||
},
|
||||
|
||||
// Used conditionally based on the value of `enable_widevine` at build time.
|
||||
// TODO(crbug.com/1379411): Use a shard to conditionally use based on
|
||||
// build-time config.
|
||||
{
|
||||
protocol: "fuchsia.media.drm.Widevine",
|
||||
from: "parent",
|
||||
to: "#realm_builder",
|
||||
availability: "optional",
|
||||
},
|
||||
|
||||
// Used conditionally based on the absence of `--headless` on the command
|
||||
// line at runtime.
|
||||
{
|
||||
protocol: [
|
||||
"fuchsia.accessibility.semantics.SemanticsManager",
|
||||
"fuchsia.tracing.provider.Registry",
|
||||
"fuchsia.ui.composition.Allocator",
|
||||
"fuchsia.ui.composition.Flatland",
|
||||
"fuchsia.ui.policy.Presenter",
|
||||
"fuchsia.ui.scenic.Scenic",
|
||||
"fuchsia.vulkan.loader.Loader",
|
||||
],
|
||||
from: "parent",
|
||||
to: "#realm_builder",
|
||||
availability: "optional",
|
||||
},
|
||||
|
||||
// Optional capabilities, dependent on availability of tracing services.
|
||||
{
|
||||
protocol: "fuchsia.tracing.perfetto.ProducerConnector",
|
||||
from: "parent",
|
||||
to: "#realm_builder",
|
||||
availability: "optional",
|
||||
},
|
||||
],
|
||||
facets: {
|
||||
"fuchsia.test.deprecated-allowed-packages": [
|
||||
"web_engine",
|
||||
"web_engine_with_webui",
|
||||
],
|
||||
"fuchsia.test": {
|
||||
"deprecated-allowed-packages": [
|
||||
"test_manager",
|
||||
"web_engine",
|
||||
"web_engine_with_webui",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"program": {
|
||||
"binary": "web_engine_shell_exec"
|
||||
},
|
||||
"sandbox": {
|
||||
"features": [
|
||||
"deprecated-ambient-replace-as-executable",
|
||||
"isolated-persistent-storage",
|
||||
"isolated-temp"
|
||||
],
|
||||
"services": [
|
||||
"fuchsia.accessibility.semantics.SemanticsManager",
|
||||
"fuchsia.buildinfo.Provider",
|
||||
"fuchsia.camera3.DeviceWatcher",
|
||||
"fuchsia.device.NameProvider",
|
||||
"fuchsia.feedback.ComponentDataRegister",
|
||||
"fuchsia.feedback.CrashReportingProductRegister",
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.hwinfo.Product",
|
||||
"fuchsia.input.virtualkeyboard.ControllerCreator",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.kernel.VmexResource",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.Audio",
|
||||
"fuchsia.media.AudioDeviceEnumerator",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.media.SessionAudioConsumerFactory",
|
||||
"fuchsia.media.drm.Widevine",
|
||||
"fuchsia.mediacodec.CodecFactory",
|
||||
"fuchsia.memorypressure.Provider",
|
||||
"fuchsia.net.interfaces.State",
|
||||
"fuchsia.net.name.Lookup",
|
||||
"fuchsia.posix.socket.Provider",
|
||||
"fuchsia.process.Launcher",
|
||||
"fuchsia.sys.Environment",
|
||||
"fuchsia.sys.Launcher",
|
||||
"fuchsia.sys.Loader",
|
||||
"fuchsia.sysmem.Allocator",
|
||||
"fuchsia.tracing.perfetto.ProducerConnector",
|
||||
"fuchsia.tracing.provider.Registry",
|
||||
"fuchsia.ui.composition.Allocator",
|
||||
"fuchsia.ui.composition.Flatland",
|
||||
"fuchsia.ui.input3.Keyboard",
|
||||
"fuchsia.ui.policy.Presenter",
|
||||
"fuchsia.ui.scenic.Scenic",
|
||||
"fuchsia.vulkan.loader.Loader",
|
||||
"fuchsia.web.ContextProvider"
|
||||
]
|
||||
}
|
||||
}
|
47
fuchsia_web/shell/web_engine_shell_for_web_instance_host.cml
Normal file
47
fuchsia_web/shell/web_engine_shell_for_web_instance_host.cml
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2023 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// A component that is launched by web_engine_shell since web_engine_shell
|
||||
// itself runs as a test component, and therefore cannot run WebInstanceHost
|
||||
// directly.
|
||||
{
|
||||
include: [
|
||||
"//fuchsia_web/webinstance_host/web_instance_host.shard.cml",
|
||||
"syslog/client.shard.cml",
|
||||
],
|
||||
program: {
|
||||
runner: "elf",
|
||||
binary: "web_engine_shell_exec",
|
||||
args: [
|
||||
// Inform web_engine_shell that it is running as the sub-process in which
|
||||
// WebInstanceHost may be used. In this scenario, the main test component
|
||||
// is running only as a launcher of this child.
|
||||
"--from-launcher",
|
||||
],
|
||||
|
||||
// Required to allow JIT in child processes such as renderers.
|
||||
// Known as 'deprecated-ambient-replace-as-executable' in CFv1.
|
||||
job_policy_ambient_mark_vmo_exec: "true",
|
||||
},
|
||||
use: [
|
||||
// Required if not run with --headless.
|
||||
{
|
||||
protocol: "fuchsia.ui.policy.Presenter",
|
||||
availability: "optional",
|
||||
},
|
||||
|
||||
// Used to hold the cdm_data directory passed to web_instance.
|
||||
{
|
||||
storage: "data",
|
||||
path: "/data",
|
||||
},
|
||||
|
||||
// Needed when launched with --enable-web-instance-tmp.
|
||||
{
|
||||
storage: "tmp",
|
||||
path: "/tmp",
|
||||
availability: "optional",
|
||||
},
|
||||
],
|
||||
}
|
@@ -491,6 +491,7 @@ fuchsia_package_installer("web_engine_installer") {
|
||||
fuchsia_package("web_engine_with_webui") {
|
||||
# TODO(fxbug.dev/100944): Add appropriate visibility when fixed.
|
||||
deps = [
|
||||
":web_instance_component",
|
||||
":web_instance_component_cfv1",
|
||||
":webui_resources",
|
||||
]
|
||||
|
@@ -77,6 +77,13 @@
|
||||
path: "/config/command-line",
|
||||
availability: "optional",
|
||||
},
|
||||
// Temporary directory specified by WebInstanceHost.set_tmp_dir.
|
||||
{
|
||||
directory: "tmp",
|
||||
path: "/tmp",
|
||||
rights: [ "rw*" ],
|
||||
availability: "optional",
|
||||
},
|
||||
{
|
||||
// Required capabilities for all configurations.
|
||||
protocol: [
|
||||
@@ -155,10 +162,5 @@
|
||||
],
|
||||
availability: "optional",
|
||||
},
|
||||
{
|
||||
storage: "cache",
|
||||
path: "/cache",
|
||||
availability: "optional",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@@ -29,7 +29,10 @@ source_set("webinstance_host") {
|
||||
"web_instance_host_internal.cc",
|
||||
"web_instance_host_internal.h",
|
||||
]
|
||||
public = [ "web_instance_host.h" ]
|
||||
public = [
|
||||
"web_instance_host.h",
|
||||
"web_instance_host_constants.h",
|
||||
]
|
||||
deps = [
|
||||
"//base:base_static",
|
||||
"//build:chromecast_buildflags",
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/check.h"
|
||||
#include "base/containers/fixed_flat_map.h"
|
||||
#include "base/fuchsia/fuchsia_logging.h"
|
||||
#include "base/fuchsia/process_context.h"
|
||||
#include "base/logging.h"
|
||||
@@ -32,6 +33,7 @@
|
||||
#include "base/types/expected.h"
|
||||
#include "components/fuchsia_component_support/serialize_arguments.h"
|
||||
#include "fuchsia_web/webengine/switches.h"
|
||||
#include "fuchsia_web/webinstance_host/web_instance_host_constants.h"
|
||||
#include "fuchsia_web/webinstance_host/web_instance_host_internal.h"
|
||||
|
||||
namespace {
|
||||
@@ -43,6 +45,10 @@ namespace fcdecl = ::fuchsia::component::decl;
|
||||
constexpr char kWebInstanceComponentUrl[] =
|
||||
"fuchsia-pkg://fuchsia.com/web_engine#meta/web_instance.cm";
|
||||
|
||||
// Test-only URL for web hosting Component instances with WebUI resources.
|
||||
const char kWebInstanceWithWebUiComponentUrl[] =
|
||||
"fuchsia-pkg://fuchsia.com/web_engine_with_webui#meta/web_instance.cm";
|
||||
|
||||
// The name of the component collection hosting the instances.
|
||||
constexpr char kCollectionName[] = "web_instances";
|
||||
|
||||
@@ -58,7 +64,8 @@ std::string InstanceNameFromId(const base::GUID& id) {
|
||||
return base::StrCat({kCollectionName, "_", id.AsLowercaseString()});
|
||||
}
|
||||
|
||||
void DestroyChild(fuchsia::component::Realm& realm, const std::string& name) {
|
||||
void DestroyInstance(fuchsia::component::Realm& realm,
|
||||
const std::string& name) {
|
||||
realm.DestroyChild(
|
||||
fcdecl::ChildRef{.name = name, .collection = kCollectionName},
|
||||
[](::fuchsia::component::Realm_DestroyChild_Result destroy_result) {
|
||||
@@ -67,8 +74,8 @@ void DestroyChild(fuchsia::component::Realm& realm, const std::string& name) {
|
||||
});
|
||||
}
|
||||
|
||||
void DestroyChildDirectory(vfs::PseudoDir* instances_dir,
|
||||
const std::string& name) {
|
||||
void DestroyInstanceDirectory(vfs::PseudoDir* instances_dir,
|
||||
const std::string& name) {
|
||||
zx_status_t status = instances_dir->RemoveEntry(name);
|
||||
ZX_DCHECK(status == ZX_OK, status);
|
||||
}
|
||||
@@ -138,13 +145,50 @@ class InstanceBuilder {
|
||||
// directory.
|
||||
void ServeCommandLine();
|
||||
|
||||
// Serves `directory` as `name` in the instance's subtree as a read-only or
|
||||
// a read-write (if `writeable`) directory. `name` is both the name of the
|
||||
// directory and the name of the capability expected by the instance.
|
||||
void ServeDirectory(base::StringPiece name,
|
||||
std::unique_ptr<vfs::internal::Directory> directory,
|
||||
// Adds offers from `void` for any offered directories that are not being
|
||||
// served for the invoker.
|
||||
void OfferMissingDirectoriesFromVoid();
|
||||
|
||||
// The directories that are optionally offered to `web_instance.cm` based on
|
||||
// the invoker's configuration.
|
||||
enum class OptionalDirectory {
|
||||
kFirst = 0,
|
||||
kCdmData = kFirst,
|
||||
kCommandLineConfig,
|
||||
kContentDirectories,
|
||||
kData,
|
||||
kTmp,
|
||||
kCount,
|
||||
};
|
||||
|
||||
// Returns a bitmask for `directory` for use with the `served_directories_`
|
||||
// bitfield.
|
||||
static uint32_t directory_bitmask(OptionalDirectory directory) {
|
||||
return 1u << static_cast<int>(directory);
|
||||
}
|
||||
|
||||
// Returns true if the host will serve `directory` to the instance.
|
||||
bool is_directory_served(OptionalDirectory directory) const {
|
||||
return served_directories_ & directory_bitmask(directory);
|
||||
}
|
||||
|
||||
// Records that `directory` will be served to the instance.
|
||||
void set_directory_served(OptionalDirectory directory) {
|
||||
served_directories_ |= directory_bitmask(directory);
|
||||
}
|
||||
|
||||
// Returns the capability and directory name for `directory`.
|
||||
static base::StringPiece GetDirectoryName(OptionalDirectory directory);
|
||||
|
||||
// Serves `directory` as `offer` in the instance's subtree as a read-only or
|
||||
// a read-write (if `writeable`) directory.
|
||||
void ServeDirectory(OptionalDirectory directory,
|
||||
std::unique_ptr<vfs::internal::Directory> fs_directory,
|
||||
bool writeable);
|
||||
|
||||
// Offers the directory `directory` from `void`.
|
||||
void OfferDirectoryFromVoid(OptionalDirectory directory);
|
||||
|
||||
// Offers the read-only directory capability named `name` from the parent.
|
||||
void OfferDirectoryFromParent(base::StringPiece name);
|
||||
|
||||
@@ -153,6 +197,10 @@ class InstanceBuilder {
|
||||
const std::string name_;
|
||||
raw_ptr<vfs::PseudoDir> instance_dir_;
|
||||
base::CommandLine args_;
|
||||
|
||||
// A bitfield of `directory_bitmask()` values indicating which optional
|
||||
// directories are being served to the instance.
|
||||
uint32_t served_directories_ = 0;
|
||||
std::vector<fuchsia::component::decl::Offer> dynamic_offers_;
|
||||
fidl::InterfaceRequest<fuchsia::web::Debug> debug_request_;
|
||||
};
|
||||
@@ -197,7 +245,7 @@ InstanceBuilder::InstanceBuilder(fuchsia::component::Realm& realm,
|
||||
|
||||
InstanceBuilder::~InstanceBuilder() {
|
||||
if (instance_dir_) {
|
||||
DestroyChildDirectory(GetWebInstancesCollectionDir(), name_);
|
||||
DestroyInstanceDirectory(GetWebInstancesCollectionDir(), name_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +270,7 @@ void InstanceBuilder::ServeRootSslCertificates() {
|
||||
void InstanceBuilder::ServeDataDirectory(
|
||||
fidl::InterfaceHandle<fuchsia::io::Directory> data_directory) {
|
||||
DCHECK(instance_dir_);
|
||||
ServeDirectory("data",
|
||||
ServeDirectory(OptionalDirectory::kData,
|
||||
std::make_unique<vfs::RemoteDir>(std::move(data_directory)),
|
||||
/*writeable=*/true);
|
||||
}
|
||||
@@ -244,7 +292,8 @@ zx_status_t InstanceBuilder::ServeContentDirectories(
|
||||
}
|
||||
}
|
||||
|
||||
ServeDirectory("content-directories", std::move(content_dirs),
|
||||
ServeDirectory(OptionalDirectory::kContentDirectories,
|
||||
std::move(content_dirs),
|
||||
/*writeable=*/false);
|
||||
return ZX_OK;
|
||||
}
|
||||
@@ -253,13 +302,14 @@ void InstanceBuilder::ServeCdmDataDirectory(
|
||||
fidl::InterfaceHandle<fuchsia::io::Directory> cdm_data_directory) {
|
||||
DCHECK(instance_dir_);
|
||||
ServeDirectory(
|
||||
"cdm_data",
|
||||
OptionalDirectory::kCdmData,
|
||||
std::make_unique<vfs::RemoteDir>(std::move(cdm_data_directory)),
|
||||
/*writeable=*/true);
|
||||
}
|
||||
|
||||
void InstanceBuilder::ServeTmpDirectory(fuchsia::io::DirectoryHandle tmp_dir) {
|
||||
ServeDirectory("tmp", std::make_unique<vfs::RemoteDir>(std::move(tmp_dir)),
|
||||
ServeDirectory(OptionalDirectory::kTmp,
|
||||
std::make_unique<vfs::RemoteDir>(std::move(tmp_dir)),
|
||||
/*writeable=*/true);
|
||||
}
|
||||
|
||||
@@ -272,9 +322,20 @@ Instance InstanceBuilder::Build(
|
||||
fidl::InterfaceRequest<fuchsia::io::Directory> services_request) {
|
||||
ServeCommandLine();
|
||||
|
||||
// Create dynamic offers from `void` for any optional directories
|
||||
// expected by web_instance.cm that are not being provided by the invoker.
|
||||
OfferMissingDirectoriesFromVoid();
|
||||
|
||||
fcdecl::Child child_decl;
|
||||
child_decl.set_name(name_);
|
||||
child_decl.set_url(kWebInstanceComponentUrl);
|
||||
// TODO(crbug.com/1010222): Make kWebInstanceComponentUrl a relative
|
||||
// component URL and remove this workaround.
|
||||
// TODO(crbug.com/1395054): Better yet, replace the with_webui component with
|
||||
// direct routing of the resources from web_engine_shell.
|
||||
child_decl.set_url(
|
||||
base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kWithWebui)
|
||||
? kWebInstanceWithWebUiComponentUrl
|
||||
: kWebInstanceComponentUrl);
|
||||
child_decl.set_startup(fcdecl::StartupMode::LAZY);
|
||||
|
||||
::fuchsia::component::CreateChildArgs create_child_args;
|
||||
@@ -335,17 +396,48 @@ void InstanceBuilder::ServeCommandLine() {
|
||||
}));
|
||||
ZX_DCHECK(status == ZX_OK, status);
|
||||
|
||||
ServeDirectory("command-line-config", std::move(config_dir),
|
||||
ServeDirectory(OptionalDirectory::kCommandLineConfig, std::move(config_dir),
|
||||
/*writeable=*/false);
|
||||
}
|
||||
|
||||
void InstanceBuilder::OfferMissingDirectoriesFromVoid() {
|
||||
for (auto directory = OptionalDirectory::kFirst;
|
||||
directory != OptionalDirectory::kCount;
|
||||
directory =
|
||||
static_cast<OptionalDirectory>(static_cast<int>(directory) + 1)) {
|
||||
if (!is_directory_served(directory)) {
|
||||
OfferDirectoryFromVoid(directory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
base::StringPiece InstanceBuilder::GetDirectoryName(
|
||||
OptionalDirectory directory) {
|
||||
static constexpr auto kNames =
|
||||
base::MakeFixedFlatMap<OptionalDirectory, base::StringPiece>({
|
||||
{OptionalDirectory::kCdmData, "cdm_data"},
|
||||
{OptionalDirectory::kCommandLineConfig, "command-line-config"},
|
||||
{OptionalDirectory::kContentDirectories, "content-directories"},
|
||||
{OptionalDirectory::kData, "data"},
|
||||
{OptionalDirectory::kTmp, "tmp"},
|
||||
});
|
||||
static_assert(kNames.size() == static_cast<int>(OptionalDirectory::kCount));
|
||||
return kNames.at(directory);
|
||||
}
|
||||
|
||||
void InstanceBuilder::ServeDirectory(
|
||||
base::StringPiece name,
|
||||
std::unique_ptr<vfs::internal::Directory> directory,
|
||||
OptionalDirectory directory,
|
||||
std::unique_ptr<vfs::internal::Directory> fs_directory,
|
||||
bool writeable) {
|
||||
DCHECK(instance_dir_);
|
||||
DCHECK(!is_directory_served(directory));
|
||||
|
||||
set_directory_served(directory);
|
||||
const auto name = GetDirectoryName(directory);
|
||||
|
||||
zx_status_t status =
|
||||
instance_dir_->AddEntry(std::string(name), std::move(directory));
|
||||
instance_dir_->AddEntry(std::string(name), std::move(fs_directory));
|
||||
ZX_DCHECK(status == ZX_OK, status);
|
||||
|
||||
dynamic_offers_.push_back(fcdecl::Offer::WithDirectory(
|
||||
@@ -360,6 +452,22 @@ void InstanceBuilder::ServeDirectory(
|
||||
.set_availability(fcdecl::Availability::REQUIRED))));
|
||||
}
|
||||
|
||||
void InstanceBuilder::OfferDirectoryFromVoid(OptionalDirectory directory) {
|
||||
DCHECK(!is_directory_served(directory));
|
||||
|
||||
// TODO(fxbug.dev/121722): Enable this once dynamic offer-from-void is
|
||||
// supported in Fuchsia.
|
||||
#if 0
|
||||
const auto name = GetDirectoryName(directory);
|
||||
dynamic_offers_.push_back(fcdecl::Offer::WithDirectory(
|
||||
std::move(fcdecl::OfferDirectory()
|
||||
.set_source(fcdecl::Ref::WithVoidType({}))
|
||||
.set_target_name(std::string(name))
|
||||
.set_dependency_type(fcdecl::DependencyType::STRONG)
|
||||
.set_availability(fcdecl::Availability::OPTIONAL))));
|
||||
#endif
|
||||
}
|
||||
|
||||
void InstanceBuilder::OfferDirectoryFromParent(base::StringPiece name) {
|
||||
DCHECK(instance_dir_);
|
||||
dynamic_offers_.push_back(fcdecl::Offer::WithDirectory(
|
||||
@@ -446,7 +554,7 @@ WebInstanceHost::WebInstanceHost() {
|
||||
|
||||
WebInstanceHost::~WebInstanceHost() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(instances_.empty());
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
zx_status_t WebInstanceHost::CreateInstanceForContextWithCopiedArgs(
|
||||
@@ -530,28 +638,29 @@ void WebInstanceHost::Initialize() {
|
||||
|
||||
void WebInstanceHost::Uninitialize() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(instances_.empty());
|
||||
|
||||
// Destroy all child instances and each one's outgoing directory subtree.
|
||||
auto* const instances_dir = GetWebInstancesCollectionDir();
|
||||
for (auto& [id, binder_ptr] : instances_) {
|
||||
const std::string name(InstanceNameFromId(id));
|
||||
if (realm_) {
|
||||
DestroyInstance(*realm_, name);
|
||||
}
|
||||
DestroyInstanceDirectory(instances_dir, name);
|
||||
binder_ptr.Unbind();
|
||||
}
|
||||
instances_.clear();
|
||||
|
||||
realm_.Unbind();
|
||||
|
||||
// Note: the entry in the outgoing directory for the top-level instances dir
|
||||
// is leaked in case multiple hosts are active in the same process.
|
||||
// is leaked in support of having multiple hosts active in a single process.
|
||||
}
|
||||
|
||||
void WebInstanceHost::OnRealmError(zx_status_t status) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
|
||||
ZX_LOG(ERROR, status) << "RealmBuilder channel error";
|
||||
|
||||
// Disconnect from all children and remove their directories.
|
||||
auto* const instances_dir = GetWebInstancesCollectionDir();
|
||||
for (auto& [id, binder_ptr] : instances_) {
|
||||
DestroyChildDirectory(instances_dir, InstanceNameFromId(id));
|
||||
binder_ptr.Unbind();
|
||||
}
|
||||
instances_.clear();
|
||||
|
||||
// Go back to the initial state.
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
@@ -561,10 +670,10 @@ void WebInstanceHost::OnComponentBinderClosed(const base::GUID& id,
|
||||
|
||||
// Destroy the child instance.
|
||||
const std::string name(InstanceNameFromId(id));
|
||||
DestroyChild(*realm_, name);
|
||||
DestroyInstance(*realm_, name);
|
||||
|
||||
// Drop the directory subtree for the child instance.
|
||||
DestroyChildDirectory(GetWebInstancesCollectionDir(), name);
|
||||
DestroyInstanceDirectory(GetWebInstancesCollectionDir(), name);
|
||||
|
||||
// Drop the hold on the instance's Binder. Note: destroying the InterfacePtr
|
||||
// here also deletes the lambda into which `id` was bound, so `id` must not
|
||||
|
@@ -77,8 +77,8 @@ class WebInstanceHost {
|
||||
// Connects to the fuchsia.component/Realm protocol.
|
||||
void Initialize();
|
||||
|
||||
// Unbinds from the fuchsia.component/Realm protocol. May only be called once
|
||||
// all web_instances have terminated.
|
||||
// Destroys all child instances and associated resources and unbinds from the
|
||||
// fuchsia.component/Realm protocol.
|
||||
void Uninitialize();
|
||||
|
||||
// Error handler for the channel to RealmBuilder.
|
||||
|
@@ -56,7 +56,6 @@
|
||||
"fuchsia.memorypressure.Provider",
|
||||
"fuchsia.process.Launcher",
|
||||
"fuchsia.sysmem.Allocator",
|
||||
"fuchsia.tracing.provider.Registry",
|
||||
],
|
||||
from: "parent",
|
||||
to: "#web_instances",
|
||||
@@ -78,12 +77,6 @@
|
||||
from: "parent",
|
||||
to: "#web_instances",
|
||||
availability: "optional",
|
||||
source_availability: "unknown",
|
||||
},
|
||||
{
|
||||
storage: "cache",
|
||||
from: "parent",
|
||||
to: "#web_instances",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@@ -434,6 +434,8 @@ void AppendDynamicServices(fuchsia::web::ContextFeatureFlags features,
|
||||
"fuchsia.media.AudioDeviceEnumerator"},
|
||||
{ContextFeatureFlags::AUDIO, ContextFeatureFlags::AUDIO,
|
||||
"fuchsia.media.SessionAudioConsumerFactory"},
|
||||
{ContextFeatureFlags::VULKAN, ContextFeatureFlags::VULKAN,
|
||||
"fuchsia.tracing.provider.Registry"},
|
||||
{ContextFeatureFlags::VULKAN, ContextFeatureFlags::VULKAN,
|
||||
"fuchsia.vulkan.loader.Loader"},
|
||||
{ContextFeatureFlags::HARDWARE_VIDEO_DECODER,
|
||||
|
@@ -146,7 +146,6 @@ std::vector<std::string> GetRequiredServicesForConfig(
|
||||
"fuchsia.settings.Display", // Used if preferred theme is DEFAULT.
|
||||
"fuchsia.sysmem.Allocator",
|
||||
"fuchsia.tracing.perfetto.ProducerConnector",
|
||||
"fuchsia.tracing.provider.Registry",
|
||||
"fuchsia.ui.scenic.Scenic"};
|
||||
|
||||
// TODO(crbug.com/1209031): Provide these conditionally, once corresponding
|
||||
@@ -186,6 +185,7 @@ std::vector<std::string> GetRequiredServicesForConfig(
|
||||
|
||||
if ((features & fuchsia::web::ContextFeatureFlags::VULKAN) ==
|
||||
fuchsia::web::ContextFeatureFlags::VULKAN) {
|
||||
services.emplace_back("fuchsia.tracing.provider.Registry");
|
||||
services.emplace_back("fuchsia.vulkan.loader.Loader");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user