Commit bd1cac0c authored by Willie Koomson's avatar Willie Koomson Committed by Commit Bot

arcvm: Launch arcvm-boot-notification-server during vm start

This change modifies ArcVmClientAdapter so that
arcvm-boot-notification-server upstart job is started during
StartMiniArc(). In UpgradeArc(), ArcVmClientAdapter sends
upgrade props to the server over the Unix socket.

make sure AVCA is able to successfully start and connect to the
server.

Bug: b:144542975
Test: Build and deploy_chrome. "restart ui", then look at logs to
Change-Id: I914770d4639eefd6cf3baa444d0288f0ae8a6dbf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2067613
Commit-Queue: Willie Koomson <wvk@google.com>
Reviewed-by: default avatarYury Khmel <khmel@chromium.org>
Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#759415}
parent 730bd577
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
#include "components/arc/session/arc_vm_client_adapter.h" #include "components/arc/session/arc_vm_client_adapter.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h> #include <time.h>
#include <set> #include <set>
#include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -16,10 +17,13 @@ ...@@ -16,10 +17,13 @@
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/no_destructor.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/launch.h" #include "base/process/launch.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
...@@ -29,7 +33,10 @@ ...@@ -29,7 +33,10 @@
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task/task_traits.h" #include "base/task/task_traits.h"
#include "base/task/thread_pool.h" #include "base/task/thread_pool.h"
#include "base/threading/platform_thread.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "chromeos/constants/chromeos_switches.h" #include "chromeos/constants/chromeos_switches.h"
#include "chromeos/cryptohome/cryptohome_parameters.h" #include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/dbus/concierge_client.h" #include "chromeos/dbus/concierge_client.h"
...@@ -51,9 +58,13 @@ constexpr const char kArcCreateDataJobName[] = "arc_2dcreate_2ddata"; ...@@ -51,9 +58,13 @@ constexpr const char kArcCreateDataJobName[] = "arc_2dcreate_2ddata";
constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy"; constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy";
constexpr const char kArcVmPerBoardFeaturesJobName[] = constexpr const char kArcVmPerBoardFeaturesJobName[] =
"arcvm_2dper_2dboard_2dfeatures"; "arcvm_2dper_2dboard_2dfeatures";
constexpr const char kArcVmBootNotificationServerJobName[] =
"arcvm_2dboot_2dnotification_2dserver";
constexpr const char kCrosSystemPath[] = "/usr/bin/crossystem"; constexpr const char kCrosSystemPath[] = "/usr/bin/crossystem";
constexpr const char kHomeDirectory[] = "/home"; constexpr const char kHomeDirectory[] = "/home";
constexpr const char kArcVmBootNotificationServerSocketPath[] =
"/run/arcvm_boot_notification_server/host.socket";
constexpr int64_t kInvalidCid = -1; constexpr int64_t kInvalidCid = -1;
...@@ -172,24 +183,15 @@ std::vector<std::string> GenerateKernelCmdline( ...@@ -172,24 +183,15 @@ std::vector<std::string> GenerateKernelCmdline(
"androidboot.boottime_offset=" + MonotonicTimestamp(), "androidboot.boottime_offset=" + MonotonicTimestamp(),
// TODO(yusukes): remove this once arcvm supports SELinux. // TODO(yusukes): remove this once arcvm supports SELinux.
"androidboot.selinux=permissive", "androidboot.selinux=permissive",
};
// Since we don't do mini VM yet, set not only |start_params| but also // Since we don't do mini VM yet, set not only |start_params| but also
// |upgrade_params| here for now. // |upgrade_params| here for now.
base::StringPrintf("androidboot.disable_boot_completed=%d", const std::vector<std::string> upgrade_props =
upgrade_params.skip_boot_completed_broadcast), GenerateUpgradeProps(upgrade_params, serial_number, "androidboot");
base::StringPrintf("androidboot.copy_packages_cache=%d", result.insert(result.end(), upgrade_props.begin(), upgrade_props.end());
static_cast<int>(upgrade_params.packages_cache_mode)),
base::StringPrintf("androidboot.skip_gms_core_cache=%d", // TODO(yusukes): Check if we need to set ro.boot.enable_adb_sideloading for
upgrade_params.skip_gms_core_cache), // ARCVM.
base::StringPrintf("androidboot.arc_demo_mode=%d",
upgrade_params.is_demo_session),
base::StringPrintf(
"androidboot.supervision.transition=%d",
static_cast<int>(upgrade_params.supervision_transition)),
"androidboot.serialno=" + serial_number,
};
// TODO(yusukes): Check if we need to set ro.boot.container_boot_type and
// ro.boot.enable_adb_sideloading for ARCVM.
// Conditionally sets some properties based on |start_params|. // Conditionally sets some properties based on |start_params|.
switch (start_params.play_store_auto_update) { switch (start_params.play_store_auto_update) {
...@@ -203,18 +205,6 @@ std::vector<std::string> GenerateKernelCmdline( ...@@ -203,18 +205,6 @@ std::vector<std::string> GenerateKernelCmdline(
break; break;
} }
// Conditionally sets more properties based on |upgrade_params|.
if (!upgrade_params.locale.empty()) {
result.push_back("androidboot.locale=" + upgrade_params.locale);
if (!upgrade_params.preferred_languages.empty()) {
result.push_back(
"androidboot.preferred_languages=" +
base::JoinString(upgrade_params.preferred_languages, ","));
}
}
// TODO(yusukes): Handle |is_account_managed| in |upgrade_params| when we
// implement apk sideloading for ARCVM.
return result; return result;
} }
...@@ -298,6 +288,81 @@ int GetSystemPropertyInt(const std::string& property) { ...@@ -298,6 +288,81 @@ int GetSystemPropertyInt(const std::string& property) {
return base::StringToInt(output, &output_int) ? output_int : -1; return base::StringToInt(output, &output_int) ? output_int : -1;
} }
const sockaddr_un* GetArcVmBootNotificationServerAddress() {
static struct sockaddr_un address {
.sun_family = AF_UNIX,
.sun_path = "/run/arcvm_boot_notification_server/host.socket"
};
return &address;
}
// Connects to UDS socket at |kArcVmBootNotificationServerSocketPath|.
// Returns the connected socket fd if successful, or else an invalid fd. This
// function can only be called with base::MayBlock().
base::ScopedFD ConnectToArcVmBootNotificationServer() {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::WILL_BLOCK);
base::ScopedFD fd(socket(AF_UNIX, SOCK_STREAM, 0));
if (!fd.is_valid()) {
PLOG(ERROR) << "Failed to create Unix socket";
return {};
}
if (HANDLE_EINTR(connect(fd.get(),
reinterpret_cast<const sockaddr*>(
GetArcVmBootNotificationServerAddress()),
sizeof(sockaddr_un)))) {
PLOG(ERROR) << "Unable to connect to "
<< kArcVmBootNotificationServerSocketPath;
return {};
}
return fd;
}
// Connects to arcvm-boot-notification-server to verify that it is listening.
// When this function is called, the server has just started and may not be
// listening on the socket yet, so this function will retry connecting for up
// to 20s, with exponential backoff. This function can only be called with
// base::MayBlock().
bool IsArcVmBootNotificationServerListening() {
const base::ElapsedTimer timer;
constexpr base::TimeDelta limit = base::TimeDelta::FromSeconds(20);
base::TimeDelta sleep_duration = base::TimeDelta::FromMilliseconds(100);
do {
if (ConnectToArcVmBootNotificationServer().is_valid())
return true;
LOG(ERROR) << "Retrying to connect to boot notification server in "
<< sleep_duration;
base::PlatformThread::Sleep(sleep_duration);
sleep_duration *= 2;
} while (timer.Elapsed() < limit);
return false;
}
// Sends upgrade props to arcvm-boot-notification-server over socket at
// |kArcVmBootNotificationServerSocketPath|. This function can only be called
// with base::MayBlock().
bool SendUpgradePropsToArcVmBootNotificationServer(
const UpgradeParams& params,
const std::string& serial_number) {
std::string props = base::JoinString(
GenerateUpgradeProps(params, serial_number, "ro.boot"), "\n");
base::ScopedFD fd = ConnectToArcVmBootNotificationServer();
if (!fd.is_valid())
return false;
if (!base::WriteFileDescriptor(fd.get(), props.c_str(), props.size())) {
PLOG(ERROR) << "Unable to write props to "
<< kArcVmBootNotificationServerSocketPath;
return false;
}
return true;
}
} // namespace } // namespace
class ArcVmClientAdapter : public ArcClientAdapter, class ArcVmClientAdapter : public ArcClientAdapter,
...@@ -451,13 +516,60 @@ class ArcVmClientAdapter : public ArcClientAdapter, ...@@ -451,13 +516,60 @@ class ArcVmClientAdapter : public ArcClientAdapter,
void OnArcVmServerProxyJobStopped(chromeos::VoidDBusMethodCallback callback, void OnArcVmServerProxyJobStopped(chromeos::VoidDBusMethodCallback callback,
bool result) { bool result) {
// Ignore |result| since it can be false when the proxy job has already been
// stopped for other reasons, but it's not considered as an error.
VLOG(1) << "OnArcVmServerProxyJobStopped: job " VLOG(1) << "OnArcVmServerProxyJobStopped: job "
<< (result ? "stopped" : "not running?"); << (result ? "stopped" : "not running?");
should_notify_observers_ = true; should_notify_observers_ = true;
// Always run the |callback| with true ignoring the |result|. |result| can
// be false when the proxy job has already been stopped for other reasons, // Kill a stale arcvm-boot-notification-server job
// but it's not considered as an error. chromeos::UpstartClient::Get()->StopJob(
kArcVmBootNotificationServerJobName, /*environment=*/{},
base::BindOnce(
&ArcVmClientAdapter::OnArcVmBootNotificationServerStopped,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void OnArcVmBootNotificationServerStopped(
chromeos::VoidDBusMethodCallback callback,
bool result) {
VLOG(1) << "OnArcVmBootNotificationServerStopped: job "
<< (result ? "stopped" : "not running?");
VLOG(1) << "Starting arcvm-boot-notification-server";
chromeos::UpstartClient::Get()->StartJob(
kArcVmBootNotificationServerJobName, /*environment=*/{},
base::BindOnce(
&ArcVmClientAdapter::OnArcVmBootNotificationServerStarted,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void OnArcVmBootNotificationServerStarted(
chromeos::VoidDBusMethodCallback callback,
bool result) {
if (!result) {
LOG(ERROR) << "Failed to start arcvm-boot-notification-server job";
std::move(callback).Run(false);
return;
}
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&IsArcVmBootNotificationServerListening),
base::BindOnce(
&ArcVmClientAdapter::OnArcVmBootNotificationServerIsListening,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void OnArcVmBootNotificationServerIsListening(
chromeos::VoidDBusMethodCallback callback,
bool result) {
if (!result) {
LOG(ERROR) << "Failed to connect to arcvm-boot-notification-server";
std::move(callback).Run(false);
return;
}
std::move(callback).Run(true); std::move(callback).Run(true);
} }
...@@ -596,6 +708,16 @@ class ArcVmClientAdapter : public ArcClientAdapter, ...@@ -596,6 +708,16 @@ class ArcVmClientAdapter : public ArcClientAdapter,
start_request, start_request,
base::BindOnce(&ArcVmClientAdapter::OnStartArcVmReply, base::BindOnce(&ArcVmClientAdapter::OnStartArcVmReply,
weak_factory_.GetWeakPtr(), std::move(callback))); weak_factory_.GetWeakPtr(), std::move(callback)));
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
base::BindOnce(&SendUpgradePropsToArcVmBootNotificationServer, params,
serial_number_),
base::BindOnce([](bool result) {
VLOG(1)
<< "Sending upgrade props to arcvm-boot-notification-server was "
<< (result ? "successful" : "unsuccessful");
}));
} }
void OnStartArcVmReply( void OnStartArcVmReply(
...@@ -684,4 +806,50 @@ std::unique_ptr<ArcClientAdapter> CreateArcVmClientAdapterForTesting( ...@@ -684,4 +806,50 @@ std::unique_ptr<ArcClientAdapter> CreateArcVmClientAdapterForTesting(
return std::make_unique<ArcVmClientAdapter>(rewriter); return std::make_unique<ArcVmClientAdapter>(rewriter);
} }
void SetArcVmBootNotificationServerAddressForTesting(
const std::string& new_address) {
sockaddr_un* address =
const_cast<sockaddr_un*>(GetArcVmBootNotificationServerAddress());
DCHECK_GE(sizeof(address->sun_path), new_address.size());
memset(address->sun_path, 0, sizeof(address->sun_path));
// |new_address| may contain '\0' if it is an abstract socket address, so use
// memcpy instead of strcpy.
memcpy(address->sun_path, new_address.data(), new_address.size());
}
std::vector<std::string> GenerateUpgradeProps(
const UpgradeParams& upgrade_params,
const std::string& serial_number,
const std::string& prefix) {
std::vector<std::string> result = {
base::StringPrintf("%s.disable_boot_completed=%d", prefix.c_str(),
upgrade_params.skip_boot_completed_broadcast),
base::StringPrintf("%s.copy_packages_cache=%d", prefix.c_str(),
static_cast<int>(upgrade_params.packages_cache_mode)),
base::StringPrintf("%s.skip_gms_core_cache=%d", prefix.c_str(),
upgrade_params.skip_gms_core_cache),
base::StringPrintf("%s.arc_demo_mode=%d", prefix.c_str(),
upgrade_params.is_demo_session),
base::StringPrintf(
"%s.supervision.transition=%d", prefix.c_str(),
static_cast<int>(upgrade_params.supervision_transition)),
base::StringPrintf("%s.serialno=%s", prefix.c_str(),
serial_number.c_str()),
};
// Conditionally sets more properties based on |upgrade_params|.
if (!upgrade_params.locale.empty()) {
result.push_back(base::StringPrintf("%s.locale=%s", prefix.c_str(),
upgrade_params.locale.c_str()));
if (!upgrade_params.preferred_languages.empty()) {
result.push_back(base::StringPrintf(
"%s.preferred_languages=%s", prefix.c_str(),
base::JoinString(upgrade_params.preferred_languages, ",").c_str()));
}
}
// TODO(yusukes): Handle |is_managed_account| in |upgrade_params|.
return result;
}
} // namespace arc } // namespace arc
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define COMPONENTS_ARC_SESSION_ARC_VM_CLIENT_ADAPTER_H_ #define COMPONENTS_ARC_SESSION_ARC_VM_CLIENT_ADAPTER_H_
#include <memory> #include <memory>
#include <string>
#include "base/callback.h" #include "base/callback.h"
#include "components/arc/session/arc_client_adapter.h" #include "components/arc/session/arc_client_adapter.h"
...@@ -13,6 +14,8 @@ ...@@ -13,6 +14,8 @@
namespace arc { namespace arc {
struct UpgradeParams;
// Enum that describes which native bridge mode is used to run arm binaries on // Enum that describes which native bridge mode is used to run arm binaries on
// x86. // x86.
enum class ArcBinaryTranslationType { enum class ArcBinaryTranslationType {
...@@ -29,6 +32,16 @@ using FileSystemStatusRewriter = ...@@ -29,6 +32,16 @@ using FileSystemStatusRewriter =
std::unique_ptr<ArcClientAdapter> CreateArcVmClientAdapterForTesting( std::unique_ptr<ArcClientAdapter> CreateArcVmClientAdapterForTesting(
const FileSystemStatusRewriter& rewriter); const FileSystemStatusRewriter& rewriter);
// Sets the path of the boot notification server socket for testing.
void SetArcVmBootNotificationServerAddressForTesting(const std::string& path);
// Generates a list of props from |upgrade_params|, each of which takes the form
// "prefix.prop_name=value"
std::vector<std::string> GenerateUpgradeProps(
const UpgradeParams& upgrade_params,
const std::string& serial_number,
const std::string& prefix);
} // namespace arc } // namespace arc
#endif // COMPONENTS_ARC_SESSION_ARC_VM_CLIENT_ADAPTER_H_ #endif // COMPONENTS_ARC_SESSION_ARC_VM_CLIENT_ADAPTER_H_
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include "components/arc/session/arc_vm_client_adapter.h" #include "components/arc/session/arc_vm_client_adapter.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
...@@ -18,8 +21,12 @@ ...@@ -18,8 +21,12 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/scoped_run_loop_timeout.h"
#include "base/threading/simple_thread.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "chromeos/cryptohome/cryptohome_parameters.h" #include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/debug_daemon/fake_debug_daemon_client.h" #include "chromeos/dbus/debug_daemon/fake_debug_daemon_client.h"
...@@ -39,6 +46,11 @@ constexpr const char kArcCreateDataJobName[] = "arc_2dcreate_2ddata"; ...@@ -39,6 +46,11 @@ constexpr const char kArcCreateDataJobName[] = "arc_2dcreate_2ddata";
constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy"; constexpr const char kArcVmServerProxyJobName[] = "arcvm_2dserver_2dproxy";
constexpr const char kArcVmPerBoardFeaturesJobName[] = constexpr const char kArcVmPerBoardFeaturesJobName[] =
"arcvm_2dper_2dboard_2dfeatures"; "arcvm_2dper_2dboard_2dfeatures";
constexpr const char kArcVmBootNotificationServerJobName[] =
"arcvm_2dboot_2dnotification_2dserver";
constexpr const size_t kUnixMaxPathLen = sizeof(((sockaddr_un*)0)->sun_path);
constexpr const char kArcVmBootNotificationServerAddress[kUnixMaxPathLen] =
"\0test_arcvm_boot_notification_server";
constexpr const char kUserIdHash[] = "this_is_a_valid_user_id_hash"; constexpr const char kUserIdHash[] = "this_is_a_valid_user_id_hash";
constexpr const char kSerialNumber[] = "AAAABBBBCCCCDDDD1234"; constexpr const char kSerialNumber[] = "AAAABBBBCCCCDDDD1234";
...@@ -120,6 +132,123 @@ class TestConciergeClient : public chromeos::FakeConciergeClient { ...@@ -120,6 +132,123 @@ class TestConciergeClient : public chromeos::FakeConciergeClient {
DISALLOW_COPY_AND_ASSIGN(TestConciergeClient); DISALLOW_COPY_AND_ASSIGN(TestConciergeClient);
}; };
// A fake ArcVmBootNotificationServer that listens on an UDS and records
// connections and the data sent to it.
class TestArcVmBootNotificationServer {
public:
TestArcVmBootNotificationServer() = default;
~TestArcVmBootNotificationServer() { Stop(); }
TestArcVmBootNotificationServer(const TestArcVmBootNotificationServer&) =
delete;
TestArcVmBootNotificationServer& operator=(
const TestArcVmBootNotificationServer&) = delete;
// Creates a socket and binds it to a name in the abstract namespace, then
// starts listening to the socket on another thread.
void Start() {
fd_.reset(socket(AF_UNIX, SOCK_STREAM, 0));
ASSERT_TRUE(fd_.is_valid());
sockaddr_un addr{.sun_family = AF_UNIX};
memcpy(addr.sun_path, kArcVmBootNotificationServerAddress,
sizeof(kArcVmBootNotificationServerAddress));
ASSERT_EQ(HANDLE_EINTR(bind(fd_.get(), reinterpret_cast<sockaddr*>(&addr),
sizeof(sockaddr_un))),
0);
ASSERT_EQ(HANDLE_EINTR(listen(fd_.get(), 5)), 0);
thread_.Start();
}
// Shuts down the socket and joins the listening thread.
void Stop() {
if (!thread_.HasBeenStarted() || thread_.HasBeenJoined())
return;
delegate_.RequestExit();
// Shutdown socket; if child thread is blocked on accept(), this will
// wake up the thread.
shutdown(fd_.get(), SHUT_RDWR);
thread_.Join();
}
int connection_count() {
base::AutoLock lock(lock_);
return num_connections_;
}
std::string received_data() {
base::AutoLock lock(lock_);
return received_;
}
private:
class Delegate : public base::DelegateSimpleThread::Delegate {
public:
explicit Delegate(TestArcVmBootNotificationServer* parent)
: parent_(parent) {}
~Delegate() override = default;
Delegate(const Delegate&) = delete;
Delegate& operator=(const Delegate&) = delete;
void Run() override {
int fd = parent_->fd_.get();
while (true) {
{
base::AutoLock lock(lock_);
if (return_flag_)
return;
}
base::ScopedFD client_fd(HANDLE_EINTR(accept(fd, nullptr, nullptr)));
if (!client_fd.is_valid())
continue;
parent_->IncrementConnectionCount();
// Attempt to read from connection until EOF
std::string out;
char buf[256];
while (true) {
ssize_t len = HANDLE_EINTR(read(client_fd.get(), buf, sizeof(buf)));
if (len <= 0)
break;
out.append(buf, len);
}
parent_->AppendReceivedData(out);
}
}
void RequestExit() {
base::AutoLock lock(lock_);
return_flag_ = true;
}
private:
base::Lock lock_;
bool return_flag_ = false;
TestArcVmBootNotificationServer* const parent_;
};
void IncrementConnectionCount() {
base::AutoLock lock(lock_);
++num_connections_;
}
void AppendReceivedData(const std::string& data) {
base::AutoLock lock(lock_);
received_.append(data);
}
base::Lock lock_;
base::ScopedFD fd_;
Delegate delegate_{this};
base::DelegateSimpleThread thread_{&delegate_, "listen thread"};
int num_connections_ = 0;
std::string received_;
};
class ArcVmClientAdapterTest : public testing::Test, class ArcVmClientAdapterTest : public testing::Test,
public ArcClientAdapter::Observer { public ArcClientAdapter::Observer {
public: public:
...@@ -141,9 +270,8 @@ class ArcVmClientAdapterTest : public testing::Test, ...@@ -141,9 +270,8 @@ class ArcVmClientAdapterTest : public testing::Test,
void SetUp() override { void SetUp() override {
run_loop_ = std::make_unique<base::RunLoop>(); run_loop_ = std::make_unique<base::RunLoop>();
adapter_ = CreateArcVmClientAdapterForTesting( adapter_ = CreateArcVmClientAdapterForTesting(base::BindRepeating(
base::BindRepeating(&ArcVmClientAdapterTest::RewriteStatus, &ArcVmClientAdapterTest::RewriteStatus, base::Unretained(this)));
base::Unretained(this)));
arc_instance_stopped_called_ = false; arc_instance_stopped_called_ = false;
adapter_->AddObserver(this); adapter_->AddObserver(this);
ASSERT_TRUE(dir_.CreateUniqueTempDir()); ASSERT_TRUE(dir_.CreateUniqueTempDir());
...@@ -161,6 +289,12 @@ class ArcVmClientAdapterTest : public testing::Test, ...@@ -161,6 +289,12 @@ class ArcVmClientAdapterTest : public testing::Test,
// Reset to the original behavior. // Reset to the original behavior.
RemoveUpstartStartStopJobFailures(); RemoveUpstartStartStopJobFailures();
boot_server_ = std::make_unique<TestArcVmBootNotificationServer>();
boot_server_->Start();
SetArcVmBootNotificationServerAddressForTesting(
std::string(kArcVmBootNotificationServerAddress,
sizeof(kArcVmBootNotificationServerAddress)));
} }
void TearDown() override { void TearDown() override {
...@@ -313,6 +447,10 @@ class ArcVmClientAdapterTest : public testing::Test, ...@@ -313,6 +447,10 @@ class ArcVmClientAdapterTest : public testing::Test,
chromeos::DBusThreadManager::Get()->GetConciergeClient()); chromeos::DBusThreadManager::Get()->GetConciergeClient());
} }
TestArcVmBootNotificationServer* boot_notification_server() {
return boot_server_.get();
}
void set_host_rootfs_writable(bool host_rootfs_writable) { void set_host_rootfs_writable(bool host_rootfs_writable) {
host_rootfs_writable_ = host_rootfs_writable; host_rootfs_writable_ = host_rootfs_writable;
} }
...@@ -343,6 +481,8 @@ class ArcVmClientAdapterTest : public testing::Test, ...@@ -343,6 +481,8 @@ class ArcVmClientAdapterTest : public testing::Test,
bool host_rootfs_writable_; bool host_rootfs_writable_;
bool system_image_ext_format_; bool system_image_ext_format_;
std::unique_ptr<TestArcVmBootNotificationServer> boot_server_;
DISALLOW_COPY_AND_ASSIGN(ArcVmClientAdapterTest); DISALLOW_COPY_AND_ASSIGN(ArcVmClientAdapterTest);
}; };
...@@ -963,5 +1103,47 @@ TEST_F(ArcVmClientAdapterTest, BintaryTranslationTypeNoNativeBridgeExperiment) { ...@@ -963,5 +1103,47 @@ TEST_F(ArcVmClientAdapterTest, BintaryTranslationTypeNoNativeBridgeExperiment) {
"androidboot.native_bridge=libhoudini.so")); "androidboot.native_bridge=libhoudini.so"));
} }
// Tests that ArcVmClientAdapter connects to the boot notification server
// twice: once in StartMiniArc to check that it is listening, and the second
// time in UpgradeArc to send props.
TEST_F(ArcVmClientAdapterTest, TestConnectToBootNotificationServer) {
SetValidUserInfo();
StartMiniArc();
EXPECT_EQ(boot_notification_server()->connection_count(), 1);
EXPECT_TRUE(boot_notification_server()->received_data().empty());
UpgradeParams params = GetPopulatedUpgradeParams();
UpgradeArcWithParams(true, params);
base::ThreadPoolInstance::Get()->FlushForTesting();
EXPECT_EQ(boot_notification_server()->connection_count(), 2);
EXPECT_FALSE(boot_notification_server()->received_data().empty());
// Compare received data to expected output
std::string expected_props = base::JoinString(
GenerateUpgradeProps(params, kSerialNumber, "ro.boot"), "\n");
EXPECT_EQ(boot_notification_server()->received_data(), expected_props);
}
// Tests that StartMiniArc fails when the boot notification server's Upstart
// job fails.
TEST_F(ArcVmClientAdapterTest, TestBootNotificationServerUpstartJobFails) {
InjectUpstartStartJobFailure(kArcVmBootNotificationServerJobName);
StartMiniArcWithParams(false, {});
}
// Tests that StartMiniArc fails when the boot notification server is not
// listening.
TEST_F(ArcVmClientAdapterTest, TestBootNotificationServerIsNotListening) {
boot_notification_server()->Stop();
// Change timeout to 26 seconds to allow for exponential backoff.
base::test::ScopedRunLoopTimeout timeout(FROM_HERE,
base::TimeDelta::FromSeconds(26));
StartMiniArcWithParams(false, {});
}
} // namespace } // namespace
} // namespace arc } // namespace arc
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