Commit 2222a4c5 authored by Hidehiko Abe's avatar Hidehiko Abe Committed by Chromium LUCI CQ

Lacros initialization with out-band file.

Currently, startup data is passed from ash-chrome to lacros-chrome
via LacroChromeService::Init() Mojo call. This requires Mojo initialization
so that the data is available only after that.
However, there are some needs that the data would like to be available
earlier.

In order to support that situation, this CL introduces another approach,
where ash-chrome dumps the serialized data into a memory backed file
and lacros-chrome inherits its file descriptor.

For backward compatibility, both lacros-chrome and ash-chrome supports
older protocol, i.e. LacrosChromeService::Init() for now,
while it is now deprecated.
Thus, any {old,new} {lacros-chrome,ash-chrome} combination should work.
It is planned to remove the older protocol support, when newer/older
chromes are distributed enough.

BUG=1155494
TEST=Ran tryjob. Ran {old,new} {lacros-chrome,ash-chrome} combinations
     on DUTs to make sure lacros-chrome can be launched successfully
     via Shelf icon and mojo_connection_lacros_launcher.py script.

Change-Id: I09c7004d07cec9a58ccfc7ee24c0e256149e4951
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2573264
Commit-Queue: Hidehiko Abe <hidehiko@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarYuke Liao <liaoyuke@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarMattias Nissler <mnissler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835744}
parent d3f8e5f0
......@@ -36,14 +36,27 @@ import sys
import subprocess
def _ReceiveFD(sock):
"""Receives a FD from ash-chrome that will be used to launch lacros-chrome.
# contextlib.nullcontext is introduced in 3.7, while Python version on
# CrOS is still 3.6. This is for backward compatibility.
class NullContext:
def __init__(self, enter_ret=None):
self.enter_ret = enter_ret
def __enter__(self):
return self.enter_ret
def __exit__(self, exc_type, exc_value, trace):
pass
def _ReceiveFDs(sock):
"""Receives FDs from ash-chrome that will be used to launch lacros-chrome.
Args:
sock: A connected unix domain socket.
Returns:
An integer represeting the received file descriptor.
File objects for the mojo connection and maybe startup data file.
"""
# This function is borrowed from with modifications:
# https://docs.python.org/3/library/socket.html#socket.socket.recvmsg
......@@ -53,12 +66,27 @@ def _ReceiveFD(sock):
version, ancdata, _, _ = sock.recvmsg(1, socket.CMSG_LEN(fds.itemsize))
for cmsg_level, cmsg_type, cmsg_data in ancdata:
if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
assert len(cmsg_data) == fds.itemsize, 'Expecting exactly 1 FD'
fds.frombytes(cmsg_data[:fds.itemsize])
# New ash-chrome returns two FDs: one for mojo connection, and the second
# for the startup data FD. Old one returns only the mojo connection.
# TODO(crbug.com/1156033): Clean up the code after dropping the
# old protocol support.
assert len(cmsg_data) in (fds.itemsize, fds.itemsize *
2), ('Expecting exactly 1 or 2 FDs')
fds.frombytes(cmsg_data[:])
assert version == b'\x00', 'Expecting version code to be 0'
assert len(list(fds)) == 1, 'Expecting exactly 1 FD'
return os.fdopen(list(fds)[0])
assert len(fds) in (1, 2), 'Expecting exactly 1 or 2 FDs'
mojo_fd = os.fdopen(fds[0])
startup_fd = None if len(fds) < 2 else os.fdopen(fds[1])
return mojo_fd, startup_fd
def _MaybeClosing(fileobj):
"""Returns closing context manager, if given fileobj is not None.
If the given fileobj is none, return nullcontext.
"""
return (contextlib.closing if fileobj else NullContext)(fileobj)
def Main():
......@@ -71,20 +99,26 @@ def Main():
required=True,
help='Absolute path to the socket that were used to start ash-chrome, '
'for example: "/tmp/lacros.socket"')
args = arg_parser.parse_known_args()
flags, args = arg_parser.parse_known_args()
assert 'XDG_RUNTIME_DIR' in os.environ
assert os.environ.get('EGL_PLATFORM') == 'surfaceless'
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
sock.connect(args[0].socket_path.as_posix())
file_obj = _ReceiveFD(sock)
assert file_obj, ('Failed to connect to the socket: %s' %
args[0].socket_path.as_posix())
with contextlib.closing(file_obj):
cmd = args[1] + ['--mojo-platform-channel-handle=%d' % file_obj.fileno()]
proc = subprocess.Popen(cmd, pass_fds=(file_obj.fileno(), ))
sock.connect(flags.socket_path.as_posix())
mojo_connection, startup_connection = _ReceiveFDs(sock)
assert mojo_connection, ('Failed to connect to the socket: %s' %
flags.socket_path.as_posix())
with _MaybeClosing(mojo_connection), _MaybeClosing(startup_connection):
cmd = args + [
'--mojo-platform-channel-handle=%d' % mojo_connection.fileno()
]
pass_fds = [mojo_connection.fileno()]
if startup_connection:
cmd.append('--cros-startup-data-fd=%d' % startup_connection.fileno())
pass_fds.append(startup_connection.fileno())
proc = subprocess.Popen(cmd, pass_fds=pass_fds)
return proc.wait()
......
......@@ -232,6 +232,7 @@ source_set("chromeos") {
"//chromeos/services/secure_channel/public/cpp/client",
"//chromeos/services/secure_channel/public/mojom",
"//chromeos/settings",
"//chromeos/startup:constants",
"//chromeos/system",
"//chromeos/timezone",
"//chromeos/tpm",
......
......@@ -26,6 +26,7 @@
#include "base/process/process_handle.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
......@@ -38,6 +39,7 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/startup/startup_switches.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
#include "google_apis/google_api_keys.h"
......@@ -350,6 +352,18 @@ void BrowserManager::StartWithLogFile(base::ScopedFD logfd) {
options.fds_to_remap.push_back(std::make_pair(logfd.get(), STDERR_FILENO));
}
base::ScopedFD startup_fd =
browser_util::CreateStartupData(environment_provider_.get());
if (startup_fd.is_valid()) {
// Hardcoded to use FD 3 to make the ash-chrome's behavior more predictable.
// Lacros-chrome should not depend on the hardcoded value though. Instead
// it should take a look at the value passed via the command line flag.
constexpr int kStartupDataFD = 3;
argv.push_back(base::StringPrintf(
"--%s=%d", chromeos::switches::kCrosStartupDataFD, kStartupDataFD));
options.fds_to_remap.emplace_back(startup_fd.get(), kStartupDataFD);
}
// Set up Mojo channel.
base::CommandLine command_line(argv);
LOG(WARNING) << "Launching lacros with command: "
......
......@@ -4,12 +4,17 @@
#include "chrome/browser/chromeos/crosapi/browser_util.h"
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <utility>
#include "base/callback.h"
#include "base/containers/flat_map.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/process/process_handle.h"
#include "base/strings/string_util.h"
......@@ -197,7 +202,13 @@ SendMojoInvitationToLacrosChrome(
invitation.AttachMessagePipe(0 /* token */), /*version=*/0));
lacros_chrome_service.set_disconnect_handler(
std::move(mojo_disconnected_callback));
lacros_chrome_service->Init(GetLacrosInitParams(environment_provider));
// This is for backward compatibility.
// TODO(crbug.com/1156033): Remove InitDeperecated() invocation when lacros
// becomes new enough.
lacros_chrome_service->InitDeprecated(
GetLacrosInitParams(environment_provider));
lacros_chrome_service->RequestAshChromeServiceReceiver(
std::move(ash_chrome_service_callback));
mojo::OutgoingInvitation::Send(std::move(invitation),
......@@ -206,5 +217,31 @@ SendMojoInvitationToLacrosChrome(
return lacros_chrome_service;
}
base::ScopedFD CreateStartupData(EnvironmentProvider* environment_provider) {
auto data = GetLacrosInitParams(environment_provider);
std::vector<uint8_t> serialized =
crosapi::mojom::LacrosInitParams::Serialize(&data);
base::ScopedFD fd(memfd_create("startup_data", 0));
if (!fd.is_valid()) {
PLOG(ERROR) << "Failed to create a memory backed file";
return base::ScopedFD();
}
if (!base::WriteFileDescriptor(
fd.get(), reinterpret_cast<const char*>(serialized.data()),
serialized.size())) {
LOG(ERROR) << "Failed to dump the serialized startup data";
return base::ScopedFD();
}
if (lseek(fd.get(), 0, SEEK_SET) < 0) {
PLOG(ERROR) << "Failed to reset the FD position";
return base::ScopedFD();
}
return fd;
}
} // namespace browser_util
} // namespace crosapi
......@@ -79,6 +79,11 @@ SendMojoInvitationToLacrosChrome(
void(mojo::PendingReceiver<crosapi::mojom::AshChromeService>)>
ash_chrome_service_callback);
// Creates a memory backed file containing the serialized |params|,
// and returns its FD.
base::ScopedFD CreateStartupData(
::crosapi::EnvironmentProvider* environment_provider);
} // namespace browser_util
} // namespace crosapi
......
......@@ -107,8 +107,16 @@ void TestMojoConnectionManager::OnTestingSocketAvailable() {
&TestMojoConnectionManager::OnAshChromeServiceReceiverReceived,
weak_factory_.GetWeakPtr()));
base::ScopedFD startup_fd =
browser_util::CreateStartupData(environment_provider_.get());
if (!startup_fd.is_valid()) {
LOG(ERROR) << "Failed to create startup data";
return;
}
std::vector<base::ScopedFD> fds;
fds.emplace_back(channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD());
fds.push_back(channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD());
fds.push_back(std::move(startup_fd));
// Version of protocol Chrome is using.
uint8_t protocol_version = 0;
......
......@@ -23,6 +23,7 @@
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/startup/startup_switches.h"
#include "mojo/public/cpp/platform/named_platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/platform/socket_utils_posix.h"
......@@ -41,7 +42,7 @@ class TestLacrosChromeService : public crosapi::mojom::LacrosChromeService {
~TestLacrosChromeService() override = default;
void Init(crosapi::mojom::LacrosInitParamsPtr params) override {
void InitDeprecated(crosapi::mojom::LacrosInitParamsPtr params) override {
init_is_called_ = true;
}
......@@ -134,16 +135,19 @@ TEST_F(TestMojoConnectionManagerTest, ConnectWithLacrosChrome) {
run_loop2.Run();
EXPECT_EQ(1, size);
EXPECT_EQ(0u, buf[0]);
ASSERT_EQ(1u, descriptors.size());
ASSERT_EQ(2u, descriptors.size());
// Test launches lacros-chrome as child process.
base::LaunchOptions options;
options.fds_to_remap.emplace_back(descriptors[0].get(), descriptors[0].get());
base::CommandLine lacros_cmd(base::GetMultiProcessTestChildBaseCommandLine());
lacros_cmd.AppendSwitchASCII(mojo::PlatformChannel::kHandleSwitch,
base::NumberToString(descriptors[0].release()));
base::NumberToString(descriptors[0].get()));
lacros_cmd.AppendSwitchASCII(chromeos::switches::kCrosStartupDataFD,
base::NumberToString(descriptors[1].get()));
base::Process lacros_process =
base::SpawnMultiProcessTestChild("LacrosMain", lacros_cmd, options);
descriptors.clear(); // Close descriptors.
// lacros-chrome accepts the invitation to establish mojo connection with
// ash-chrome.
......
......@@ -176,6 +176,7 @@ test("chromeos_unittests") {
"//chromeos/network:unit_tests",
"//chromeos/services:unit_tests",
"//chromeos/settings:unit_tests",
"//chromeos/startup:unit_tests",
"//chromeos/system:unit_tests",
"//chromeos/timezone:unit_tests",
"//chromeos/tpm:unit_tests",
......
......@@ -230,9 +230,12 @@ struct LacrosInitParams {
// are accessed from ash-chrome.
[Stable, Uuid="4e04dc16-b34c-40fd-9e3f-3c55c2c6cf91"]
interface LacrosChromeService {
// DEPRECATED: in M89. In new versions, memory backed file based
// initialization data passing is used.
//
// Ash-chrome can pass initialize parameters via this method.
// The parameters are available on lacros-chrome startup.
Init@2(LacrosInitParams params);
InitDeprecated@2(LacrosInitParams params);
// Returns the pending_receiver of AshChromeService.
// Ash-chrome is expected to call this method on initialization.
......
......@@ -15,6 +15,7 @@ component("lacros") {
deps = [
"//base",
"//chromeos/crosapi/mojom",
"//chromeos/startup",
"//mojo/public/cpp/bindings",
]
sources = [
......
......@@ -12,6 +12,7 @@
#include "base/task/thread_pool.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/lacros/lacros_chrome_service_delegate.h"
#include "chromeos/startup/startup.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "url/gurl.h"
......@@ -35,6 +36,23 @@ crosapi::mojom::LacrosInfoPtr ToMojo(const std::string& lacros_version) {
return mojo_lacros_info;
}
// Reads and parses the startup data to LacrosInitParams.
// If data is missing, or failed to parse, returns a null StructPtr.
crosapi::mojom::LacrosInitParamsPtr ReadStartupLacrosInitParams() {
base::Optional<std::string> content = ReadStartupData();
if (!content)
return {};
crosapi::mojom::LacrosInitParamsPtr result;
if (!crosapi::mojom::LacrosInitParams::Deserialize(
content->data(), content->size(), &result)) {
LOG(ERROR) << "Failed to parse startup data";
return {};
}
return result;
}
} // namespace
// This class that holds all state that is affine to a single, never-blocking
......@@ -50,7 +68,6 @@ class LacrosChromeServiceNeverBlockingState
: owner_sequence_(owner_sequence),
owner_(owner),
init_params_(init_params) {
DCHECK(init_params);
DETACH_FROM_SEQUENCE(sequence_checker_);
}
~LacrosChromeServiceNeverBlockingState() override {
......@@ -58,8 +75,9 @@ class LacrosChromeServiceNeverBlockingState
}
// crosapi::mojom::LacrosChromeService:
void Init(crosapi::mojom::LacrosInitParamsPtr params) override {
*init_params_ = std::move(params);
void InitDeprecated(crosapi::mojom::LacrosInitParamsPtr params) override {
if (init_params_)
*init_params_ = std::move(params);
initialized_.Signal();
}
......@@ -244,7 +262,7 @@ class LacrosChromeServiceNeverBlockingState
// Owned by LacrosChromeServiceImpl.
crosapi::mojom::LacrosInitParamsPtr* const init_params_;
// Lock to wait for Init() invocation.
// Lock to wait for InitDeprecated() invocation.
// Because the parameters are needed before starting the affined thread's
// message pumping, it is necessary to use sync primitive here, instead.
base::WaitableEvent initialized_;
......@@ -265,9 +283,13 @@ LacrosChromeServiceImpl::LacrosChromeServiceImpl(
: delegate_(std::move(delegate)),
sequenced_state_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {
if (g_disable_all_crosapi_for_tests) {
// Tests don't call LacrosChromeService::Init(), so provide LacrosInitParams
// with default values.
// Tests don't call LacrosChromeService::InitDeprecated(), so provide
// LacrosInitParams with default values.
init_params_ = crosapi::mojom::LacrosInitParams::New();
} else {
// Try to read the startup data. If ash-chrome is too old, the data
// may not available, then fallback to the older approach.
init_params_ = ReadStartupLacrosInitParams();
}
// The sequence on which this object was constructed, and thus affine to.
......@@ -281,7 +303,8 @@ LacrosChromeServiceImpl::LacrosChromeServiceImpl(
sequenced_state_ = std::unique_ptr<LacrosChromeServiceNeverBlockingState,
base::OnTaskRunnerDeleter>(
new LacrosChromeServiceNeverBlockingState(
affine_sequence, weak_factory_.GetWeakPtr(), &init_params_),
affine_sequence, weak_factory_.GetWeakPtr(),
init_params_.is_null() ? &init_params_ : nullptr),
base::OnTaskRunnerDeleter(never_blocking_sequence_));
weak_sequenced_state_ = sequenced_state_->GetWeakPtr();
......@@ -307,7 +330,11 @@ void LacrosChromeServiceImpl::BindReceiver(
FROM_HERE, base::BindOnce(&LacrosChromeServiceNeverBlockingState::
BindLacrosChromeServiceReceiver,
weak_sequenced_state_, std::move(receiver)));
sequenced_state_->WaitForInit();
// If ash-chrome is too old, LacrosInitParams may not be passed from
// a memory backed file directly. Then, try to wait for InitDeprecated()
// invocation for backward compatibility.
if (!init_params_)
sequenced_state_->WaitForInit();
DCHECK(init_params_);
delegate_->OnInitialized(*init_params_);
did_bind_receiver_ = true;
......
......@@ -216,6 +216,16 @@ class COMPONENT_EXPORT(CHROMEOS_LACROS) LacrosChromeServiceImpl {
// if this method returns true.
bool IsOnLacrosStartupAvailable();
// Returns LacrosInitParams which is passed from ash-chrome. On launching
// lacros-chrome from ash-chrome, ash-chrome creates a memory backed file
// serializes the LacrosInitParams to it, and the forked/executed
// lacros-chrome process inherits the file descriptor. The data is read
// in the constructor so is available from the beginning.
// Note that, in older versions, ash-chrome passes the data via
// LacrosChromeService::Init() mojo call to lacros-chrome. That case is still
// handled for backward compatibility, and planned to be removed in the
// future (crbug.com/1156033). Though, until the removal, it is recommended
// to consider both cases, specifically, at least not to cause a crash.
const crosapi::mojom::LacrosInitParams* init_params() const {
return init_params_.get();
}
......
# Copyright 2018 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.
component("startup") {
output_name = "chromeos_startup"
defines = [ "IS_CHROMEOS_STARTUP_IMPL" ]
deps = [
":constants",
"//base",
]
sources = [
"startup.cc",
"startup.h",
]
}
component("constants") {
output_name = "chromeos_startup_constants"
defines = [ "IS_CHROMEOS_STARTUP_CONSTANTS_IMPL" ]
deps = [ "//base" ]
sources = [
"startup_switches.cc",
"startup_switches.h",
]
}
source_set("unit_tests") {
testonly = true
deps = [
":constants",
":startup",
"//base",
"//base/test:test_support",
"//testing/gtest",
]
sources = [ "startup_unittest.cc" ]
}
hidehiko@chromium.org
// Copyright 2020 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.
#include "chromeos/startup/startup.h"
#include <stdio.h>
#include <utility>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "chromeos/startup/startup_switches.h"
namespace chromeos {
base::Optional<std::string> ReadStartupData() {
auto* command_line = base::CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kCrosStartupDataFD))
return base::nullopt;
int raw_fd = 0;
if (!base::StringToInt(
command_line->GetSwitchValueASCII(switches::kCrosStartupDataFD),
&raw_fd)) {
LOG(ERROR) << "Unrecognizable value for --" << switches::kCrosStartupDataFD;
return base::nullopt;
}
base::ScopedFILE file(fdopen(raw_fd, "r"));
std::string content;
if (!base::ReadStreamToString(file.get(), &content)) {
LOG(ERROR) << "Failed to read startup data";
return base::nullopt;
}
return base::make_optional(std::move(content));
}
} // namespace chromeos
// Copyright 2020 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.
#ifndef CHROMEOS_STARTUP_STARTUP_H_
#define CHROMEOS_STARTUP_STARTUP_H_
#include <string>
#include "base/component_export.h"
#include "base/optional.h"
namespace chromeos {
// Reads the startup data. The FD to be read for the startup data should be
// specified via the kCrosStartupDataFD command line flag. This function
// consumes the FD, so this must not be called twice in a process.
COMPONENT_EXPORT(CHROMEOS_STARTUP)
base::Optional<std::string> ReadStartupData();
} // namespace chromeos
#endif // CHROMEOS_STARTUP_STARTUP_H_
// Copyright 2020 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.
#include "chromeos/startup/startup_switches.h"
namespace chromeos {
namespace switches {
// FD pointing a (memory backed) file containing the startup data.
const char kCrosStartupDataFD[] = "cros-startup-data-fd";
} // namespace switches
} // namespace chromeos
// Copyright 2020 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.
#ifndef CHROMEOS_STARTUP_STARTUP_SWITCHES_H_
#define CHROMEOS_STARTUP_STARTUP_SWITCHES_H_
#include "base/component_export.h"
namespace chromeos {
namespace switches {
COMPONENT_EXPORT(CHROMEOS_STARTUP_CONSTANTS)
extern const char kCrosStartupDataFD[];
} // namespace switches
} // namespace chromeos
#endif // CHROMEOS_STARTUP_STARTUP_SWITCHES_H_
// Copyright 2020 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.
#include "chromeos/startup/startup.h"
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/optional.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/test/scoped_command_line.h"
#include "chromeos/startup/startup_switches.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace {
base::ScopedFD CreateMemoryFile(const base::StringPiece content) {
base::ScopedFD file(memfd_create("test", 0));
if (!file.is_valid()) {
PLOG(ERROR) << "Failed to create a memory file";
return base::ScopedFD();
}
if (!base::WriteFileDescriptor(file.get(), content.data(), content.size())) {
LOG(ERROR) << "Failed to write the data";
return base::ScopedFD();
}
// Reset the cursor.
if (lseek(file.get(), 0, SEEK_SET) < 0) {
PLOG(ERROR) << "Failed to reset the file position";
return base::ScopedFD();
}
return file;
}
} // namespace
TEST(ChromeOSStartup, Startup) {
constexpr char kTestData[] = "test test test test";
base::ScopedFD file = CreateMemoryFile(kTestData);
base::test::ScopedCommandLine scoped_command_line;
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// Release the FD. The FD is consumed in ReadStartupData().
command_line->AppendSwitchASCII(switches::kCrosStartupDataFD,
base::NumberToString(file.release()));
base::Optional<std::string> data = ReadStartupData();
EXPECT_EQ(data, kTestData);
}
TEST(ChromeOSStartup, NoFlag) {
EXPECT_FALSE(ReadStartupData());
}
} // namespace chromeos
......@@ -4,6 +4,7 @@ include_rules = [
# These are low-level system APIs on ChromeOS that need to be available
# everywhere.
"+chromeos/lacros/lacros_chrome_service_impl.h",
"+chromeos/startup/startup_switches.h",
"+content/public",
"+components/discardable_memory/service",
......
......@@ -119,6 +119,7 @@
#include "base/files/file_path.h"
#include "base/files/scoped_file.h"
#include "chromeos/lacros/lacros_chrome_service_impl.h"
#include "chromeos/startup/startup_switches.h" // nogncheck
#include "mojo/public/cpp/platform/named_platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/platform/socket_utils_posix.h"
......@@ -385,11 +386,22 @@ void BrowserTestBase::SetUp() {
PLOG(ERROR) << "Error receiving message from the socket";
ASSERT_EQ(1, size);
EXPECT_EQ(0u, buf[0]);
ASSERT_EQ(1u, descriptors.size());
// Older ash-chrome gives us one FD, which will become a Mojo connection.
// Newer ash-chrome gives us another FD, too, which contains startup
// data.
// TODO(crbug.com/1156033): Clean up when both ash-chrome and
// lacros-chrome become new enough.
ASSERT_LE(descriptors.size(), 2u);
// It's OK to release the FD because lacros-chrome's code will consume it.
command_line->AppendSwitchASCII(
mojo::PlatformChannel::kHandleSwitch,
base::NumberToString(descriptors[0].release()));
if (descriptors.size() == 2) {
// Ok to release the FD here, too.
command_line->AppendSwitchASCII(
chromeos::switches::kCrosStartupDataFD,
base::NumberToString(descriptors[1].release()));
}
}
}
#endif
......
......@@ -627,7 +627,10 @@ static_library("test_support") {
}
if (is_chromeos_lacros) {
deps += [ "//chromeos/lacros" ]
deps += [
"//chromeos/lacros",
"//chromeos/startup:constants",
]
}
if (is_linux || is_chromeos) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment