1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/fuchsia/test_component_context_for_process.h"
6
7 #include <fidl/fuchsia.io/cpp/hlcpp_conversion.h>
8 #include <fuchsia/io/cpp/fidl.h>
9 #include <lib/fdio/directory.h>
10 #include <lib/fidl/cpp/interface_handle.h>
11 #include <lib/sys/cpp/component_context.h>
12
13 #include "base/files/file_enumerator.h"
14 #include "base/fuchsia/filtered_service_directory.h"
15 #include "base/fuchsia/fuchsia_logging.h"
16 #include "base/fuchsia/process_context.h"
17 #include "base/run_loop.h"
18
19 namespace base {
20
TestComponentContextForProcess(InitialState initial_state)21 TestComponentContextForProcess::TestComponentContextForProcess(
22 InitialState initial_state) {
23 // TODO(https://crbug.com/1038786): Migrate to sys::ComponentContextProvider
24 // once it provides access to an sys::OutgoingDirectory or PseudoDir through
25 // which to publish additional_services().
26
27 // Set up |incoming_services_| to use the ServiceDirectory from the current
28 // default ComponentContext to fetch services from.
29 context_services_ = std::make_unique<FilteredServiceDirectory>(
30 base::ComponentContextForProcess()->svc());
31
32 // Push all services from /svc to the test context if requested.
33 if (initial_state == InitialState::kCloneAll) {
34 // Calling stat() in /svc is problematic; see https://fxbug.dev/100207. Tell
35 // the enumerator not to recurse, to return both files and directories, and
36 // to report only the names of entries.
37 base::FileEnumerator file_enum(base::FilePath("/svc"), /*recursive=*/false,
38 base::FileEnumerator::NAMES_ONLY);
39 for (auto file = file_enum.Next(); !file.empty(); file = file_enum.Next()) {
40 AddService(file.BaseName().value());
41 }
42 }
43
44 // Create a ServiceDirectory backed by the contents of |incoming_directory|.
45 fidl::InterfaceHandle<::fuchsia::io::Directory> incoming_directory;
46 zx_status_t status =
47 context_services_->ConnectClient(incoming_directory.NewRequest());
48 ZX_CHECK(status == ZX_OK, status) << "ConnectClient failed";
49 auto incoming_services =
50 std::make_shared<sys::ServiceDirectory>(std::move(incoming_directory));
51
52 // Create the ComponentContext with the incoming directory connected to the
53 // directory of |context_services_| published by the test, and with a request
54 // for the process' root outgoing directory.
55 fidl::InterfaceHandle<::fuchsia::io::Directory> published_root_directory;
56 old_context_ = ReplaceComponentContextForProcessForTest(
57 std::make_unique<sys::ComponentContext>(
58 std::move(incoming_services), published_root_directory.NewRequest()));
59
60 // Connect to the "/svc" directory of the |published_root_directory| and wrap
61 // that into a ServiceDirectory.
62 fidl::InterfaceHandle<::fuchsia::io::Directory> published_services;
63 status = fdio_service_connect_at(
64 published_root_directory.channel().get(), "svc",
65 published_services.NewRequest().TakeChannel().release());
66 ZX_CHECK(status == ZX_OK, status) << "fdio_service_connect_at() to /svc";
67 published_services_ =
68 std::make_shared<sys::ServiceDirectory>(std::move(published_services));
69 published_services_natural_ =
70 fidl::HLCPPToNatural(published_services_->CloneChannel());
71 }
72
~TestComponentContextForProcess()73 TestComponentContextForProcess::~TestComponentContextForProcess() {
74 ReplaceComponentContextForProcessForTest(std::move(old_context_));
75 }
76
additional_services()77 sys::OutgoingDirectory* TestComponentContextForProcess::additional_services() {
78 return context_services_->outgoing_directory();
79 }
80
AddService(const base::StringPiece service)81 void TestComponentContextForProcess::AddService(
82 const base::StringPiece service) {
83 zx_status_t status = context_services_->AddService(service);
84 ZX_CHECK(status == ZX_OK, status) << "AddService(" << service << ") failed";
85 }
86
AddServices(base::span<const base::StringPiece> services)87 void TestComponentContextForProcess::AddServices(
88 base::span<const base::StringPiece> services) {
89 for (auto service : services)
90 AddService(service);
91 }
92
93 fidl::UnownedClientEnd<fuchsia_io::Directory>
published_services_natural()94 TestComponentContextForProcess::published_services_natural() {
95 return published_services_natural_.borrow();
96 }
97
98 } // namespace base
99