Commit 7df1bd05 authored by Chris Morin's avatar Chris Morin Committed by Commit Bot

arc: simplify upgrade failure handling

Simplify the upgrade failure handling by ignoring the result of the dbus
call, and instead waiting for the ArcInstanceStopped signal before
signaling a failure. Also check for disk space in Chrome instead of in
session_manager.

This is the first change in a series that will have Chrome call to
Upstart directly to start the container, cutting out session_manager
entirely.

BUG=b:133248517
TEST=Run test cases and manually test container startup/shutdown.

Change-Id: I7c5ef4be82b5fbb2deca1fae7a2a0ebc06952e26
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1623631
Commit-Queue: Chris Morin <cmtm@chromium.org>
Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#662829}
parent cae728d5
...@@ -580,25 +580,17 @@ void FakeSessionManagerClient::StartArcMiniContainer( ...@@ -580,25 +580,17 @@ void FakeSessionManagerClient::StartArcMiniContainer(
void FakeSessionManagerClient::UpgradeArcContainer( void FakeSessionManagerClient::UpgradeArcContainer(
const login_manager::UpgradeArcContainerRequest& request, const login_manager::UpgradeArcContainerRequest& request,
base::OnceClosure success_callback, VoidDBusMethodCallback callback) {
UpgradeErrorCallback error_callback) {
last_upgrade_arc_request_ = request; last_upgrade_arc_request_ = request;
if (!arc_available_) { PostReply(FROM_HERE, std::move(callback), !force_upgrade_failure_);
PostReply(FROM_HERE, std::move(error_callback), false); if (force_upgrade_failure_) {
return; // Emulate ArcInstanceStopped signal propagation.
}
if (low_disk_) {
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&FakeSessionManagerClient::NotifyArcInstanceStopped, base::BindOnce(&FakeSessionManagerClient::NotifyArcInstanceStopped,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr()));
login_manager::ArcContainerStopReason::LOW_DISK_SPACE));
PostReply(FROM_HERE, std::move(error_callback), true);
return;
} }
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(success_callback));
} }
void FakeSessionManagerClient::StopArcInstance( void FakeSessionManagerClient::StopArcInstance(
...@@ -613,8 +605,8 @@ void FakeSessionManagerClient::StopArcInstance( ...@@ -613,8 +605,8 @@ void FakeSessionManagerClient::StopArcInstance(
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&FakeSessionManagerClient::NotifyArcInstanceStopped, base::BindOnce(&FakeSessionManagerClient::NotifyArcInstanceStopped,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr()));
login_manager::ArcContainerStopReason::USER_REQUEST));
container_running_ = false; container_running_ = false;
} }
...@@ -637,10 +629,9 @@ void FakeSessionManagerClient::GetArcStartTime( ...@@ -637,10 +629,9 @@ void FakeSessionManagerClient::GetArcStartTime(
arc_available_ ? base::make_optional(arc_start_time_) : base::nullopt); arc_available_ ? base::make_optional(arc_start_time_) : base::nullopt);
} }
void FakeSessionManagerClient::NotifyArcInstanceStopped( void FakeSessionManagerClient::NotifyArcInstanceStopped() {
login_manager::ArcContainerStopReason reason) {
for (auto& observer : observers_) for (auto& observer : observers_)
observer.ArcInstanceStopped(reason); observer.ArcInstanceStopped();
} }
bool FakeSessionManagerClient::GetFlagsForUser( bool FakeSessionManagerClient::GetFlagsForUser(
......
...@@ -112,8 +112,7 @@ class COMPONENT_EXPORT(SESSION_MANAGER) FakeSessionManagerClient ...@@ -112,8 +112,7 @@ class COMPONENT_EXPORT(SESSION_MANAGER) FakeSessionManagerClient
VoidDBusMethodCallback callback) override; VoidDBusMethodCallback callback) override;
void UpgradeArcContainer( void UpgradeArcContainer(
const login_manager::UpgradeArcContainerRequest& request, const login_manager::UpgradeArcContainerRequest& request,
base::OnceClosure success_callback, VoidDBusMethodCallback callback) override;
UpgradeErrorCallback error_callback) override;
void StopArcInstance(VoidDBusMethodCallback callback) override; void StopArcInstance(VoidDBusMethodCallback callback) override;
void SetArcCpuRestriction( void SetArcCpuRestriction(
login_manager::ContainerCpuRestrictionState restriction_state, login_manager::ContainerCpuRestrictionState restriction_state,
...@@ -123,7 +122,7 @@ class COMPONENT_EXPORT(SESSION_MANAGER) FakeSessionManagerClient ...@@ -123,7 +122,7 @@ class COMPONENT_EXPORT(SESSION_MANAGER) FakeSessionManagerClient
void GetArcStartTime(DBusMethodCallback<base::TimeTicks> callback) override; void GetArcStartTime(DBusMethodCallback<base::TimeTicks> callback) override;
// Notifies observers as if ArcInstanceStopped signal is received. // Notifies observers as if ArcInstanceStopped signal is received.
void NotifyArcInstanceStopped(login_manager::ArcContainerStopReason); void NotifyArcInstanceStopped();
// Returns true if flags for |cryptohome_id| have been set. If the return // Returns true if flags for |cryptohome_id| have been set. If the return
// value is |true|, |*out_flags_for_user| is filled with the flags passed to // value is |true|, |*out_flags_for_user| is filled with the flags passed to
...@@ -230,12 +229,13 @@ class COMPONENT_EXPORT(SESSION_MANAGER) FakeSessionManagerClient ...@@ -230,12 +229,13 @@ class COMPONENT_EXPORT(SESSION_MANAGER) FakeSessionManagerClient
} }
void set_arc_available(bool available) { arc_available_ = available; } void set_arc_available(bool available) { arc_available_ = available; }
void set_force_upgrade_failure(bool force_upgrade_failure) {
force_upgrade_failure_ = force_upgrade_failure;
}
void set_arc_start_time(base::TimeTicks arc_start_time) { void set_arc_start_time(base::TimeTicks arc_start_time) {
arc_start_time_ = arc_start_time; arc_start_time_ = arc_start_time;
} }
void set_low_disk(bool low_disk) { low_disk_ = low_disk; }
void set_force_state_keys_missing(bool force_state_keys_missing) { void set_force_state_keys_missing(bool force_state_keys_missing) {
force_state_keys_missing_ = force_state_keys_missing; force_state_keys_missing_ = force_state_keys_missing;
} }
...@@ -289,9 +289,9 @@ class COMPONENT_EXPORT(SESSION_MANAGER) FakeSessionManagerClient ...@@ -289,9 +289,9 @@ class COMPONENT_EXPORT(SESSION_MANAGER) FakeSessionManagerClient
bool force_state_keys_missing_ = false; bool force_state_keys_missing_ = false;
bool arc_available_ = false; bool arc_available_ = false;
bool force_upgrade_failure_ = false;
base::TimeTicks arc_start_time_; base::TimeTicks arc_start_time_;
bool low_disk_ = false;
bool container_running_ = false; bool container_running_ = false;
// Contains last request passed to StartArcMiniContainer // Contains last request passed to StartArcMiniContainer
......
...@@ -419,10 +419,8 @@ class SessionManagerClientImpl : public SessionManagerClient { ...@@ -419,10 +419,8 @@ class SessionManagerClientImpl : public SessionManagerClient {
void UpgradeArcContainer( void UpgradeArcContainer(
const login_manager::UpgradeArcContainerRequest& request, const login_manager::UpgradeArcContainerRequest& request,
base::OnceClosure success_callback, VoidDBusMethodCallback callback) override {
UpgradeErrorCallback error_callback) override { DCHECK(!callback.is_null());
DCHECK(!success_callback.is_null());
DCHECK(!error_callback.is_null());
dbus::MethodCall method_call( dbus::MethodCall method_call(
login_manager::kSessionManagerInterface, login_manager::kSessionManagerInterface,
login_manager::kSessionManagerUpgradeArcContainer); login_manager::kSessionManagerUpgradeArcContainer);
...@@ -430,11 +428,10 @@ class SessionManagerClientImpl : public SessionManagerClient { ...@@ -430,11 +428,10 @@ class SessionManagerClientImpl : public SessionManagerClient {
writer.AppendProtoAsArrayOfBytes(request); writer.AppendProtoAsArrayOfBytes(request);
session_manager_proxy_->CallMethodWithErrorResponse( session_manager_proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&SessionManagerClientImpl::OnUpgradeArcContainer, base::BindOnce(&SessionManagerClientImpl::OnVoidMethod,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
std::move(success_callback), std::move(error_callback)));
} }
void StopArcInstance(VoidDBusMethodCallback callback) override { void StopArcInstance(VoidDBusMethodCallback callback) override {
...@@ -728,19 +725,8 @@ class SessionManagerClientImpl : public SessionManagerClient { ...@@ -728,19 +725,8 @@ class SessionManagerClientImpl : public SessionManagerClient {
} }
void ArcInstanceStoppedReceived(dbus::Signal* signal) { void ArcInstanceStoppedReceived(dbus::Signal* signal) {
dbus::MessageReader reader(signal);
auto reason = login_manager::ArcContainerStopReason::CRASH;
uint32_t value = 0;
if (reader.PopUint32(&value)) {
reason = static_cast<login_manager::ArcContainerStopReason>(value);
} else {
LOG(ERROR) << "Invalid signal: " << signal->ToString();
return;
}
for (auto& observer : observers_) for (auto& observer : observers_)
observer.ArcInstanceStopped(reason); observer.ArcInstanceStopped();
} }
// Called when the object is connected to the signal. // Called when the object is connected to the signal.
...@@ -795,21 +781,6 @@ class SessionManagerClientImpl : public SessionManagerClient { ...@@ -795,21 +781,6 @@ class SessionManagerClientImpl : public SessionManagerClient {
std::move(callback).Run(base::TimeTicks::FromInternalValue(ticks)); std::move(callback).Run(base::TimeTicks::FromInternalValue(ticks));
} }
void OnUpgradeArcContainer(base::OnceClosure success_callback,
UpgradeErrorCallback error_callback,
dbus::Response* response,
dbus::ErrorResponse* error) {
if (!response) {
LOG(ERROR) << "Failed to call UpgradeArcContainer: "
<< (error ? error->ToString() : "(null)");
std::move(error_callback)
.Run(error && error->GetErrorName() ==
login_manager::dbus_error::kLowFreeDisk);
return;
}
std::move(success_callback).Run();
}
dbus::ObjectProxy* session_manager_proxy_ = nullptr; dbus::ObjectProxy* session_manager_proxy_ = nullptr;
std::unique_ptr<BlockingMethodCaller> blocking_method_caller_; std::unique_ptr<BlockingMethodCaller> blocking_method_caller_;
base::ObserverList<Observer>::Unchecked observers_; base::ObserverList<Observer>::Unchecked observers_;
......
...@@ -73,11 +73,7 @@ class COMPONENT_EXPORT(SESSION_MANAGER) SessionManagerClient { ...@@ -73,11 +73,7 @@ class COMPONENT_EXPORT(SESSION_MANAGER) SessionManagerClient {
virtual void EmitLoginPromptVisibleCalled() {} virtual void EmitLoginPromptVisibleCalled() {}
// Called when the ARC instance is stopped after it had already started. // Called when the ARC instance is stopped after it had already started.
// |clean| is true if the instance was stopped as a result of an explicit virtual void ArcInstanceStopped() {}
// request, false if it died unexpectedly.
// See details for StartArcInstanceCallback.
virtual void ArcInstanceStopped(
login_manager::ArcContainerStopReason reason) {}
}; };
// Interface for performing actions on behalf of the stub implementation. // Interface for performing actions on behalf of the stub implementation.
...@@ -338,16 +334,14 @@ class COMPONENT_EXPORT(SESSION_MANAGER) SessionManagerClient { ...@@ -338,16 +334,14 @@ class COMPONENT_EXPORT(SESSION_MANAGER) SessionManagerClient {
const login_manager::StartArcMiniContainerRequest& request, const login_manager::StartArcMiniContainerRequest& request,
VoidDBusMethodCallback callback) = 0; VoidDBusMethodCallback callback) = 0;
// UpgradeArcContainer upgrades a mini-container to a full ARC container. In // UpgradeArcContainer upgrades a mini-container to a full ARC container. On
// case of success, success_callback is called. In case of error, // upgrade failure, the container will be shutdown. The container shutdown
// error_callback will be called with a |low_free_disk_space| signaling // will trigger the ArcInstanceStopped signal (as usual). There are no
// whether the failure was due to low free disk space. // guarantees over whether this |callback| is invoked or the
using UpgradeErrorCallback = // ArcInstanceStopped signal is received first.
base::OnceCallback<void(bool low_free_disk_space)>;
virtual void UpgradeArcContainer( virtual void UpgradeArcContainer(
const login_manager::UpgradeArcContainerRequest& request, const login_manager::UpgradeArcContainerRequest& request,
base::OnceClosure success_callback, VoidDBusMethodCallback callback) = 0;
UpgradeErrorCallback error_callback) = 0;
// Asynchronously stops the ARC instance. Upon completion, invokes // Asynchronously stops the ARC instance. Upon completion, invokes
// |callback| with the result; true on success, false on failure (either // |callback| with the result; true on success, false on failure (either
......
...@@ -8,18 +8,12 @@ ...@@ -8,18 +8,12 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/optional.h"
#include "chromeos/dbus/login_manager/arc.pb.h"
#include "chromeos/dbus/session_manager/session_manager_client.h" #include "chromeos/dbus/session_manager/session_manager_client.h"
namespace arc { namespace arc {
// TODO(yusukes): Move the enum and proto in system_api/ from login_manager's
// namespace to arc and remove all the type aliases.
using ArcContainerStopReason = login_manager::ArcContainerStopReason;
using StartArcMiniContainerRequest = using StartArcMiniContainerRequest =
login_manager::StartArcMiniContainerRequest; login_manager::StartArcMiniContainerRequest;
using UpgradeArcContainerRequest = login_manager::UpgradeArcContainerRequest; using UpgradeArcContainerRequest = login_manager::UpgradeArcContainerRequest;
...@@ -30,7 +24,7 @@ class ArcClientAdapter { ...@@ -30,7 +24,7 @@ class ArcClientAdapter {
class Observer { class Observer {
public: public:
virtual ~Observer() = default; virtual ~Observer() = default;
virtual void ArcInstanceStopped(ArcContainerStopReason stop_reason) = 0; virtual void ArcInstanceStopped() = 0;
}; };
// Creates a default instance of ArcClientAdapter. // Creates a default instance of ArcClientAdapter.
...@@ -42,15 +36,9 @@ class ArcClientAdapter { ...@@ -42,15 +36,9 @@ class ArcClientAdapter {
virtual void StartMiniArc(const StartArcMiniContainerRequest& request, virtual void StartMiniArc(const StartArcMiniContainerRequest& request,
chromeos::VoidDBusMethodCallback callback) = 0; chromeos::VoidDBusMethodCallback callback) = 0;
// UpgradeArc upgrades a mini ARC instance to a full ARC instance. In case of // UpgradeArc upgrades a mini ARC instance to a full ARC instance.
// success, success_callback is called. In case of error, |error_callback|
// will be called with a |low_free_disk_space| signaling whether the failure
// was due to low free disk space.
using UpgradeErrorCallback =
base::OnceCallback<void(bool low_free_disk_space)>;
virtual void UpgradeArc(const UpgradeArcContainerRequest& request, virtual void UpgradeArc(const UpgradeArcContainerRequest& request,
base::OnceClosure success_callback, chromeos::VoidDBusMethodCallback callback) = 0;
UpgradeErrorCallback error_callback) = 0;
// Asynchronously stops the ARC instance. // Asynchronously stops the ARC instance.
virtual void StopArcInstance() = 0; virtual void StopArcInstance() = 0;
......
...@@ -37,10 +37,9 @@ class ArcContainerClientAdapter ...@@ -37,10 +37,9 @@ class ArcContainerClientAdapter
} }
void UpgradeArc(const UpgradeArcContainerRequest& request, void UpgradeArc(const UpgradeArcContainerRequest& request,
base::OnceClosure success_callback, chromeos::VoidDBusMethodCallback callback) override {
UpgradeErrorCallback error_callback) override {
chromeos::SessionManagerClient::Get()->UpgradeArcContainer( chromeos::SessionManagerClient::Get()->UpgradeArcContainer(
request, std::move(success_callback), std::move(error_callback)); request, std::move(callback));
} }
void StopArcInstance() override { void StopArcInstance() override {
...@@ -51,10 +50,9 @@ class ArcContainerClientAdapter ...@@ -51,10 +50,9 @@ class ArcContainerClientAdapter
} }
// chromeos::SessionManagerClient::Observer overrides: // chromeos::SessionManagerClient::Observer overrides:
void ArcInstanceStopped( void ArcInstanceStopped() override {
login_manager::ArcContainerStopReason stop_reason) override {
for (auto& observer : observer_list_) for (auto& observer : observer_list_)
observer.ArcInstanceStopped(stop_reason); observer.ArcInstanceStopped();
} }
private: private:
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "base/rand_util.h" #include "base/rand_util.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/system/sys_info.h"
#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 "chromeos/constants/chromeos_switches.h" #include "chromeos/constants/chromeos_switches.h"
...@@ -80,17 +81,6 @@ bool WaitForSocketReadable(int raw_socket_fd, int raw_cancel_fd) { ...@@ -80,17 +81,6 @@ bool WaitForSocketReadable(int raw_socket_fd, int raw_cancel_fd) {
return true; return true;
} }
// Returns the ArcStopReason corresponding to the ARC instance staring failure.
ArcStopReason GetArcStopReason(bool low_disk_space, bool stop_requested) {
if (stop_requested)
return ArcStopReason::SHUTDOWN;
if (low_disk_space)
return ArcStopReason::LOW_DISK_SPACE;
return ArcStopReason::GENERIC_BOOT_FAILURE;
}
// Converts ArcSupervisionTransition into // Converts ArcSupervisionTransition into
// login_manager::UpgradeArcContainerRequest_SupervisionTransition. // login_manager::UpgradeArcContainerRequest_SupervisionTransition.
login_manager::UpgradeArcContainerRequest_SupervisionTransition login_manager::UpgradeArcContainerRequest_SupervisionTransition
...@@ -126,6 +116,7 @@ class ArcSessionDelegateImpl : public ArcSessionImpl::Delegate { ...@@ -126,6 +116,7 @@ class ArcSessionDelegateImpl : public ArcSessionImpl::Delegate {
base::ScopedFD ConnectMojo(base::ScopedFD socket_fd, base::ScopedFD ConnectMojo(base::ScopedFD socket_fd,
ConnectMojoCallback callback) override; ConnectMojoCallback callback) override;
void GetLcdDensity(GetLcdDensityCallback callback) override; void GetLcdDensity(GetLcdDensityCallback callback) override;
void GetFreeDiskSpace(GetFreeDiskSpaceCallback callback) override;
version_info::Channel GetChannel() override; version_info::Channel GetChannel() override;
private: private:
...@@ -208,6 +199,15 @@ void ArcSessionDelegateImpl::GetLcdDensity(GetLcdDensityCallback callback) { ...@@ -208,6 +199,15 @@ void ArcSessionDelegateImpl::GetLcdDensity(GetLcdDensityCallback callback) {
std::move(callback))); std::move(callback)));
} }
void ArcSessionDelegateImpl::GetFreeDiskSpace(
GetFreeDiskSpaceCallback callback) {
PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&base::SysInfo::AmountOfFreeDiskSpace,
base::FilePath("/home")),
std::move(callback));
}
version_info::Channel ArcSessionDelegateImpl::GetChannel() { version_info::Channel ArcSessionDelegateImpl::GetChannel() {
return channel_; return channel_;
} }
...@@ -448,11 +448,13 @@ void ArcSessionImpl::OnMiniInstanceStarted(bool result) { ...@@ -448,11 +448,13 @@ void ArcSessionImpl::OnMiniInstanceStarted(bool result) {
DCHECK_EQ(state_, State::STARTING_MINI_INSTANCE); DCHECK_EQ(state_, State::STARTING_MINI_INSTANCE);
if (!result) { if (!result) {
OnStopped(GetArcStopReason(false, stop_requested_)); LOG(ERROR) << "Failed to start ARC mini container";
OnStopped(ArcStopReason::GENERIC_BOOT_FAILURE);
return; return;
} }
VLOG(2) << "ARC mini container has been successfully started."; VLOG(2) << "ARC mini container has been successfully started.";
state_ = State::RUNNING_MINI_INSTANCE;
if (stop_requested_) { if (stop_requested_) {
// The ARC instance has started to run. Request to stop. // The ARC instance has started to run. Request to stop.
...@@ -460,8 +462,6 @@ void ArcSessionImpl::OnMiniInstanceStarted(bool result) { ...@@ -460,8 +462,6 @@ void ArcSessionImpl::OnMiniInstanceStarted(bool result) {
return; return;
} }
state_ = State::RUNNING_MINI_INSTANCE;
if (upgrade_requested_) if (upgrade_requested_)
// RequestUpgrade() has been called during the D-Bus call. // RequestUpgrade() has been called during the D-Bus call.
DoUpgrade(); DoUpgrade();
...@@ -473,6 +473,24 @@ void ArcSessionImpl::DoUpgrade() { ...@@ -473,6 +473,24 @@ void ArcSessionImpl::DoUpgrade() {
VLOG(2) << "Upgrading an existing ARC mini instance"; VLOG(2) << "Upgrading an existing ARC mini instance";
state_ = State::STARTING_FULL_INSTANCE; state_ = State::STARTING_FULL_INSTANCE;
// Getting the free disk space doesn't take long.
delegate_->GetFreeDiskSpace(base::BindOnce(&ArcSessionImpl::OnFreeDiskSpace,
weak_factory_.GetWeakPtr()));
}
void ArcSessionImpl::OnFreeDiskSpace(int64_t space) {
// Ensure there's sufficient space on disk for the container.
if (space == -1) {
LOG(ERROR) << "Could not determine free disk space";
StopArcInstance();
return;
} else if (space < kMinimumFreeDiskSpaceBytes) {
VLOG(1) << "There is not enough disk space to start the ARC container";
insufficient_disk_space_ = true;
StopArcInstance();
return;
}
delegate_->CreateSocket(base::BindOnce(&ArcSessionImpl::OnSocketCreated, delegate_->CreateSocket(base::BindOnce(&ArcSessionImpl::OnSocketCreated,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
} }
...@@ -490,7 +508,7 @@ void ArcSessionImpl::OnSocketCreated(base::ScopedFD socket_fd) { ...@@ -490,7 +508,7 @@ void ArcSessionImpl::OnSocketCreated(base::ScopedFD socket_fd) {
if (!socket_fd.is_valid()) { if (!socket_fd.is_valid()) {
LOG(ERROR) << "ARC: Error creating socket"; LOG(ERROR) << "ARC: Error creating socket";
OnStopped(ArcStopReason::GENERIC_BOOT_FAILURE); StopArcInstance();
return; return;
} }
...@@ -535,18 +553,20 @@ void ArcSessionImpl::OnSocketCreated(base::ScopedFD socket_fd) { ...@@ -535,18 +553,20 @@ void ArcSessionImpl::OnSocketCreated(base::ScopedFD socket_fd) {
upgrade_params_.demo_session_apps_path.value()); upgrade_params_.demo_session_apps_path.value());
} }
client_->UpgradeArc( client_->UpgradeArc(request, base::BindOnce(&ArcSessionImpl::OnUpgraded,
request, weak_factory_.GetWeakPtr(),
base::BindOnce(&ArcSessionImpl::OnUpgraded, weak_factory_.GetWeakPtr(), std::move(socket_fd)));
std::move(socket_fd)),
base::BindOnce(&ArcSessionImpl::OnUpgradeError,
weak_factory_.GetWeakPtr()));
} }
void ArcSessionImpl::OnUpgraded(base::ScopedFD socket_fd) { void ArcSessionImpl::OnUpgraded(base::ScopedFD socket_fd, bool result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_EQ(state_, State::STARTING_FULL_INSTANCE); DCHECK_EQ(state_, State::STARTING_FULL_INSTANCE);
if (!result) {
LOG(ERROR) << "Failed to upgrade ARC container";
return;
}
VLOG(2) << "ARC instance is successfully upgraded."; VLOG(2) << "ARC instance is successfully upgraded.";
if (stop_requested_) { if (stop_requested_) {
...@@ -567,10 +587,6 @@ void ArcSessionImpl::OnUpgraded(base::ScopedFD socket_fd) { ...@@ -567,10 +587,6 @@ void ArcSessionImpl::OnUpgraded(base::ScopedFD socket_fd) {
} }
} }
void ArcSessionImpl::OnUpgradeError(bool low_disk_space) {
OnStopped(GetArcStopReason(low_disk_space, stop_requested_));
}
void ArcSessionImpl::OnMojoConnected( void ArcSessionImpl::OnMojoConnected(
std::unique_ptr<mojom::ArcBridgeHost> arc_bridge_host) { std::unique_ptr<mojom::ArcBridgeHost> arc_bridge_host) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
...@@ -658,30 +674,28 @@ void ArcSessionImpl::StopArcInstance() { ...@@ -658,30 +674,28 @@ void ArcSessionImpl::StopArcInstance() {
client_->StopArcInstance(); client_->StopArcInstance();
} }
void ArcSessionImpl::ArcInstanceStopped(ArcContainerStopReason stop_reason) { void ArcSessionImpl::ArcInstanceStopped() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
VLOG(1) << "Notified that ARC instance is stopped " DCHECK_NE(state_, State::STARTING_MINI_INSTANCE);
<< static_cast<uint32_t>(stop_reason); VLOG(1) << "Notified that ARC instance is stopped";
// In case that crash happens during before the Mojo channel is connected, // In case that crash happens during before the Mojo channel is connected,
// unlock the ThreadPool's thread. // unlock the ThreadPool's thread.
accept_cancel_pipe_.reset(); accept_cancel_pipe_.reset();
// TODO(hidehiko): In new D-Bus signal, more detailed reason why ARC
// container is stopped. Check it in details.
ArcStopReason reason; ArcStopReason reason;
if (stop_requested_) { if (stop_requested_) {
// If the ARC instance is stopped after its explicit request, // If the ARC instance is stopped after its explicit request,
// return SHUTDOWN. // return SHUTDOWN.
reason = ArcStopReason::SHUTDOWN; reason = ArcStopReason::SHUTDOWN;
} else if (stop_reason == ArcContainerStopReason::LOW_DISK_SPACE) { } else if (insufficient_disk_space_) {
// ARC mini container is stopped because of upgarde failure due to low // ARC mini container is stopped because of upgarde failure due to low
// disk space. // disk space.
reason = ArcStopReason::LOW_DISK_SPACE; reason = ArcStopReason::LOW_DISK_SPACE;
} else if (stop_reason != ArcContainerStopReason::CRASH) { } else if (state_ == State::STARTING_FULL_INSTANCE ||
// If the ARC instance is stopped, but it is not explicitly requested, state_ == State::CONNECTING_MOJO) {
// then this is triggered by some failure during the starting procedure. // If the ARC instance is stopped during the upgrade, but it is not
// Return GENERIC_BOOT_FAILURE for the case. // explicitly requested, return GENERIC_BOOT_FAILURE for the case.
reason = ArcStopReason::GENERIC_BOOT_FAILURE; reason = ArcStopReason::GENERIC_BOOT_FAILURE;
} else { } else {
// Otherwise, this is caused by CRASH occured inside of the ARC instance. // Otherwise, this is caused by CRASH occured inside of the ARC instance.
......
...@@ -30,6 +30,8 @@ namespace mojom { ...@@ -30,6 +30,8 @@ namespace mojom {
class ArcBridgeHost; class ArcBridgeHost;
} // namespace mojom } // namespace mojom
constexpr int64_t kMinimumFreeDiskSpaceBytes = 64 << 20; // 64MB
class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer { class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer {
public: public:
// The possible states of the session. Expected state changes are as follows. // The possible states of the session. Expected state changes are as follows.
...@@ -87,10 +89,9 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer { ...@@ -87,10 +89,9 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer {
// There is no more callback which runs on normal flow, so Stop() requests // There is no more callback which runs on normal flow, so Stop() requests
// to stop the ARC instance via SessionManager. // to stop the ARC instance via SessionManager.
// //
// Another trigger to change the state coming from outside of this class // Another trigger to change the state coming from outside of this class is an
// is an event ArcInstanceStopped() sent from SessionManager, when ARC // event, ArcInstanceStopped(), sent from SessionManager when the ARC instance
// instace unexpectedly terminates. ArcInstanceStopped() turns the state into // terminates. ArcInstanceStopped() turns the state into STOPPED immediately.
// STOPPED immediately.
// //
// In NOT_STARTED or STOPPED state, the instance can be safely destructed. // In NOT_STARTED or STOPPED state, the instance can be safely destructed.
// Specifically, in STOPPED state, there may be inflight operations or // Specifically, in STOPPED state, there may be inflight operations or
...@@ -156,6 +157,10 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer { ...@@ -156,6 +157,10 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer {
// callback will cancel the pending callback. // callback will cancel the pending callback.
virtual void GetLcdDensity(GetLcdDensityCallback callback) = 0; virtual void GetLcdDensity(GetLcdDensityCallback callback) = 0;
// Gets the available disk space under /home. The result is in bytes.
using GetFreeDiskSpaceCallback = base::OnceCallback<void(int64_t)>;
virtual void GetFreeDiskSpace(GetFreeDiskSpaceCallback callback) = 0;
// Returns the channel for the installation. // Returns the channel for the installation.
virtual version_info::Channel GetChannel() = 0; virtual version_info::Channel GetChannel() = 0;
}; };
...@@ -190,7 +195,7 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer { ...@@ -190,7 +195,7 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer {
// D-Bus callback for UpgradeArcContainer(). |socket_fd| should be a socket // D-Bus callback for UpgradeArcContainer(). |socket_fd| should be a socket
// which should be accept(2)ed to connect ArcBridgeService Mojo channel. // which should be accept(2)ed to connect ArcBridgeService Mojo channel.
void OnUpgraded(base::ScopedFD socket_fd); void OnUpgraded(base::ScopedFD socket_fd, bool result);
// D-Bus callback for UpgradeArcContainer when the upgrade fails. // D-Bus callback for UpgradeArcContainer when the upgrade fails.
// |low_free_disk_space| signals whether the failure was due to low free disk // |low_free_disk_space| signals whether the failure was due to low free disk
...@@ -205,7 +210,7 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer { ...@@ -205,7 +210,7 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer {
void StopArcInstance(); void StopArcInstance();
// ArcClientAdapter::Observer: // ArcClientAdapter::Observer:
void ArcInstanceStopped(ArcContainerStopReason stop_reason) override; void ArcInstanceStopped() override;
// Completes the termination procedure. Note that calling this may end up with // Completes the termination procedure. Note that calling this may end up with
// deleting |this| because the function calls observers' OnSessionStopped(). // deleting |this| because the function calls observers' OnSessionStopped().
...@@ -214,6 +219,9 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer { ...@@ -214,6 +219,9 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer {
// LCD density for the device is available. // LCD density for the device is available.
void OnLcdDensity(int32_t lcd_density); void OnLcdDensity(int32_t lcd_density);
// Free disk space under /home in bytes.
void OnFreeDiskSpace(int64_t space);
// Checks whether a function runs on the thread where the instance is // Checks whether a function runs on the thread where the instance is
// created. // created.
THREAD_CHECKER(thread_checker_); THREAD_CHECKER(thread_checker_);
...@@ -233,6 +241,9 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer { ...@@ -233,6 +241,9 @@ class ArcSessionImpl : public ArcSession, public ArcClientAdapter::Observer {
// Whether the full container has been requested // Whether the full container has been requested
bool upgrade_requested_ = false; bool upgrade_requested_ = false;
// Whether there's insufficient disk space to start the container.
bool insufficient_disk_space_ = false;
// In CONNECTING_MOJO state, this is set to the write side of the pipe // In CONNECTING_MOJO state, this is set to the write side of the pipe
// to notify cancelling of the procedure. // to notify cancelling of the procedure.
base::ScopedFD accept_cancel_pipe_; base::ScopedFD accept_cancel_pipe_;
......
...@@ -90,6 +90,10 @@ class FakeDelegate : public ArcSessionImpl::Delegate { ...@@ -90,6 +90,10 @@ class FakeDelegate : public ArcSessionImpl::Delegate {
lcd_density_callback_ = std::move(callback); lcd_density_callback_ = std::move(callback);
} }
void GetFreeDiskSpace(GetFreeDiskSpaceCallback callback) override {
std::move(callback).Run(free_disk_space_);
}
version_info::Channel GetChannel() override { version_info::Channel GetChannel() override {
return version_info::Channel::DEFAULT; return version_info::Channel::DEFAULT;
} }
...@@ -100,6 +104,8 @@ class FakeDelegate : public ArcSessionImpl::Delegate { ...@@ -100,6 +104,8 @@ class FakeDelegate : public ArcSessionImpl::Delegate {
std::move(lcd_density_callback_).Run(lcd_density_); std::move(lcd_density_callback_).Run(lcd_density_);
} }
void SetFreeDiskSpace(int64_t space) { free_disk_space_ = space; }
private: private:
void PostCallback(ConnectMojoCallback callback) { void PostCallback(ConnectMojoCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
...@@ -112,6 +118,7 @@ class FakeDelegate : public ArcSessionImpl::Delegate { ...@@ -112,6 +118,7 @@ class FakeDelegate : public ArcSessionImpl::Delegate {
int32_t lcd_density_ = 0; int32_t lcd_density_ = 0;
bool success_ = true; bool success_ = true;
bool suspend_ = false; bool suspend_ = false;
int64_t free_disk_space_ = kMinimumFreeDiskSpaceBytes * 2;
ConnectMojoCallback pending_callback_; ConnectMojoCallback pending_callback_;
GetLcdDensityCallback lcd_density_callback_; GetLcdDensityCallback lcd_density_callback_;
...@@ -198,10 +205,6 @@ class ArcSessionImplTest : public testing::Test { ...@@ -198,10 +205,6 @@ class ArcSessionImplTest : public testing::Test {
user_manager::UserManager::Get()); user_manager::UserManager::Get());
} }
void EmulateDBusFailure() {
chromeos::FakeSessionManagerClient::Get()->set_arc_available(false);
}
std::unique_ptr<ArcSessionImpl, ArcSessionDeleter> CreateArcSession( std::unique_ptr<ArcSessionImpl, ArcSessionDeleter> CreateArcSession(
std::unique_ptr<ArcSessionImpl::Delegate> delegate = nullptr, std::unique_ptr<ArcSessionImpl::Delegate> delegate = nullptr,
int32_t lcd_density = 160) { int32_t lcd_density = 160) {
...@@ -243,7 +246,7 @@ TEST_F(ArcSessionImplTest, MiniInstance_Success) { ...@@ -243,7 +246,7 @@ TEST_F(ArcSessionImplTest, MiniInstance_Success) {
// SessionManagerClient::StartArcMiniContainer() reports an error, causing the // SessionManagerClient::StartArcMiniContainer() reports an error, causing the
// mini-container start to fail. // mini-container start to fail.
TEST_F(ArcSessionImplTest, MiniInstance_DBusFail) { TEST_F(ArcSessionImplTest, MiniInstance_DBusFail) {
EmulateDBusFailure(); chromeos::FakeSessionManagerClient::Get()->set_arc_available(false);
auto arc_session = CreateArcSession(); auto arc_session = CreateArcSession();
TestArcSessionObserver observer(arc_session.get()); TestArcSessionObserver observer(arc_session.get());
...@@ -262,10 +265,13 @@ TEST_F(ArcSessionImplTest, MiniInstance_DBusFail) { ...@@ -262,10 +265,13 @@ TEST_F(ArcSessionImplTest, MiniInstance_DBusFail) {
// causing the container upgrade to fail to start container with reason // causing the container upgrade to fail to start container with reason
// LOW_DISK_SPACE. // LOW_DISK_SPACE.
TEST_F(ArcSessionImplTest, Upgrade_LowDisk) { TEST_F(ArcSessionImplTest, Upgrade_LowDisk) {
chromeos::FakeSessionManagerClient::Get()->set_low_disk(true); auto delegate = std::make_unique<FakeDelegate>();
delegate->SetFreeDiskSpace(kMinimumFreeDiskSpaceBytes / 2);
// Set up. Start mini-container. The mini-container doesn't use the disk, so // Set up. Start mini-container. The mini-container doesn't use the disk, so
// there being low disk space won't cause it to start. // there being low disk space won't cause it to start.
auto arc_session = CreateArcSession(); auto arc_session = CreateArcSession(std::move(delegate));
base::RunLoop run_loop; base::RunLoop run_loop;
TestArcSessionObserver observer(arc_session.get(), &run_loop); TestArcSessionObserver observer(arc_session.get(), &run_loop);
ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer)); ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer));
...@@ -306,7 +312,7 @@ TEST_F(ArcSessionImplTest, Upgrade_DBusFail) { ...@@ -306,7 +312,7 @@ TEST_F(ArcSessionImplTest, Upgrade_DBusFail) {
ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer)); ASSERT_NO_FATAL_FAILURE(SetupMiniContainer(arc_session.get(), &observer));
// Hereafter, let SessionManagerClient::UpgradeArcContainer() fail. // Hereafter, let SessionManagerClient::UpgradeArcContainer() fail.
EmulateDBusFailure(); chromeos::FakeSessionManagerClient::Get()->set_force_upgrade_failure(true);
// Then upgrade, which should fail. // Then upgrade, which should fail.
arc_session->RequestUpgrade(DefaultUpgradeParams()); arc_session->RequestUpgrade(DefaultUpgradeParams());
...@@ -514,33 +520,6 @@ TEST_F(ArcSessionImplTest, ...@@ -514,33 +520,6 @@ TEST_F(ArcSessionImplTest,
EXPECT_TRUE(observer.on_session_stopped_args()->upgrade_requested); EXPECT_TRUE(observer.on_session_stopped_args()->upgrade_requested);
} }
// Stop is requested, but at the same time
// SessionManagerClient::StartArcMiniContainer() reports an error. Then, it
// should be handled as regular SHUTDOWN, because graceful shutdown itself is
// difficult and sometimes reports unexpected error although it succeeds.
TEST_F(ArcSessionImplTest, Stop_ConflictWithFailure) {
// Let SessionManagerClient::StartArcMiniContainer() fail.
EmulateDBusFailure();
auto arc_session = CreateArcSession();
TestArcSessionObserver observer(arc_session.get());
arc_session->StartMiniInstance();
ASSERT_EQ(ArcSessionImpl::State::STARTING_MINI_INSTANCE,
arc_session->GetStateForTesting());
arc_session->Stop();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting());
ASSERT_TRUE(observer.on_session_stopped_args().has_value());
// Even if D-Bus reports an error, if Stop() is invoked, it will be handled
// as clean shutdown.
EXPECT_EQ(ArcStopReason::SHUTDOWN,
observer.on_session_stopped_args()->reason);
EXPECT_FALSE(observer.on_session_stopped_args()->was_running);
EXPECT_FALSE(observer.on_session_stopped_args()->upgrade_requested);
}
// Emulating crash. // Emulating crash.
TEST_F(ArcSessionImplTest, ArcStopInstance) { TEST_F(ArcSessionImplTest, ArcStopInstance) {
auto arc_session = CreateArcSession(); auto arc_session = CreateArcSession();
...@@ -552,8 +531,7 @@ TEST_F(ArcSessionImplTest, ArcStopInstance) { ...@@ -552,8 +531,7 @@ TEST_F(ArcSessionImplTest, ArcStopInstance) {
arc_session->GetStateForTesting()); arc_session->GetStateForTesting());
// Deliver the ArcInstanceStopped D-Bus signal. // Deliver the ArcInstanceStopped D-Bus signal.
chromeos::FakeSessionManagerClient::Get()->NotifyArcInstanceStopped( chromeos::FakeSessionManagerClient::Get()->NotifyArcInstanceStopped();
login_manager::ArcContainerStopReason::CRASH);
EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting()); EXPECT_EQ(ArcSessionImpl::State::STOPPED, arc_session->GetStateForTesting());
ASSERT_TRUE(observer.on_session_stopped_args().has_value()); ASSERT_TRUE(observer.on_session_stopped_args().has_value());
......
...@@ -13,18 +13,13 @@ ...@@ -13,18 +13,13 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "chromeos/dbus/session_manager/session_manager_client.h" #include "chromeos/dbus/login_manager/arc.pb.h"
#include "chromeos/dbus/upstart/upstart_client.h" #include "chromeos/dbus/upstart/upstart_client.h"
namespace arc { namespace arc {
namespace { namespace {
// TODO(yusukes): Move ArcContainerStopReason to arc:: and stop including
// chromeos/dbus/session_manager/session_manager_client.h.
constexpr login_manager::ArcContainerStopReason kDummyReason =
login_manager::ArcContainerStopReason::SESSION_MANAGER_SHUTDOWN;
// The conversion of upstart job names to dbus object paths is undocumented. See // The conversion of upstart job names to dbus object paths is undocumented. See
// arc_data_remover.cc for more information. // arc_data_remover.cc for more information.
constexpr char kArcVmUpstartJob[] = "arcvm"; constexpr char kArcVmUpstartJob[] = "arcvm";
...@@ -45,8 +40,7 @@ class ArcVmClientAdapter : public ArcClientAdapter { ...@@ -45,8 +40,7 @@ class ArcVmClientAdapter : public ArcClientAdapter {
} }
void UpgradeArc(const UpgradeArcContainerRequest& request, void UpgradeArc(const UpgradeArcContainerRequest& request,
base::OnceClosure success_callback, chromeos::VoidDBusMethodCallback callback) override {
UpgradeErrorCallback error_callback) override {
// TODO(yusukes): Consider doing the same as crostini rather than taking to // TODO(yusukes): Consider doing the same as crostini rather than taking to
// Upstart. // Upstart.
VLOG(1) << "Starting arcvm"; VLOG(1) << "Starting arcvm";
...@@ -57,10 +51,7 @@ class ArcVmClientAdapter : public ArcClientAdapter { ...@@ -57,10 +51,7 @@ class ArcVmClientAdapter : public ArcClientAdapter {
// arc_session_impl.cc fills the |account_id| field, and it is always // arc_session_impl.cc fills the |account_id| field, and it is always
// guaranteed that the ID is not for Incognito mode and is a valid one. // guaranteed that the ID is not for Incognito mode and is a valid one.
// TODO(yusukes): Pass other fields of the |request| to the job. // TODO(yusukes): Pass other fields of the |request| to the job.
{"CHROMEOS_USER=" + request.account_id()}, {"CHROMEOS_USER=" + request.account_id()}, std::move(callback));
base::BindOnce(&ArcVmClientAdapter::OnArcInstanceUpgraded,
weak_factory_.GetWeakPtr(), std::move(success_callback),
std::move(error_callback)));
} }
void StopArcInstance() override { void StopArcInstance() override {
...@@ -76,22 +67,12 @@ class ArcVmClientAdapter : public ArcClientAdapter { ...@@ -76,22 +67,12 @@ class ArcVmClientAdapter : public ArcClientAdapter {
} }
private: private:
void OnArcInstanceUpgraded(base::OnceClosure success_callback,
UpgradeErrorCallback error_callback,
bool result) {
VLOG(1) << "OnArcInstanceUpgraded result=" << result;
if (result)
std::move(success_callback).Run();
else
std::move(error_callback).Run(/*low_free_disk_space=*/false);
}
void OnArcInstanceStopped(bool result) { void OnArcInstanceStopped(bool result) {
VLOG(1) << "OnArcInstanceStopped result=" << result; VLOG(1) << "OnArcInstanceStopped result=" << result;
if (!result) if (!result)
LOG(WARNING) << "Failed to stop arcvm. Instance not running?"; LOG(WARNING) << "Failed to stop arcvm. Instance not running?";
for (auto& observer : observer_list_) for (auto& observer : observer_list_)
observer.ArcInstanceStopped(kDummyReason); observer.ArcInstanceStopped();
} }
// For callbacks. // For callbacks.
......
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