Commit d2b8d0b4 authored by Nicholas Verne's avatar Nicholas Verne Committed by Commit Bot

Adds a "Shut Down Linux" context menu item.

Crostini Terminal icon now has a Shut Down Linux item, which is enabled
if and only if the default vm is running for this user.
CrostiniManager now tracks |running_vms_| and updates this multimap when
vms start and stop.

Bug: 848116
Change-Id: I1130f0ff2e122828c81c286fa3a4362e3cb3138d
Reviewed-on: https://chromium-review.googlesource.com/1124065Reviewed-by: default avatarTimothy Loh <timloh@chromium.org>
Commit-Queue: Nicholas Verne <nverne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572501}
parent 71543c0a
......@@ -5025,6 +5025,9 @@ Installing Linux will download <ph name="DOWNLOAD_SIZE">$1<ex>300MB</ex></ph> of
<message name="IDS_CROSTINI_UNINSTALLER_ERROR" desc="Text shown in the Crostini uninstaller dialog when the Linux uninstall process fails.">
Error uninstalling Linux. Please try again.
</message>
<message name="IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM" desc="Text shown in the context menu for the Linux terminal app, allowing users to shut down the Linux virtual machine.">
Shut Down Linux
</message>
<!-- Time limit notification -->
<message name="IDS_SCREEN_TIME_NOTIFICATION_TITLE" desc="The title of the notification when screen usage limit reaches before locking the device.">
......
......@@ -414,6 +414,12 @@ CrostiniManager* CrostiniManager::GetInstance() {
return base::Singleton<CrostiniManager>::get();
}
bool CrostiniManager::IsVmRunning(Profile* profile, std::string vm_name) {
return running_vms_.find(std::make_pair(CryptohomeIdForProfile(profile),
std::move(vm_name))) !=
running_vms_.end();
}
CrostiniManager::CrostiniManager() : weak_ptr_factory_(this) {
// Cicerone/ConciergeClient and its observer_list_ will be destroyed together.
// We add, but don't need to remove the observer. (Doing so would force a
......@@ -632,7 +638,8 @@ void CrostiniManager::StartTerminaVm(std::string owner_id,
GetConciergeClient()->StartTerminaVm(
request,
base::BindOnce(&CrostiniManager::OnStartTerminaVm,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
weak_ptr_factory_.GetWeakPtr(), request.owner_id(),
request.name(), std::move(callback)));
}
void CrostiniManager::StopVm(Profile* profile,
......@@ -644,13 +651,16 @@ void CrostiniManager::StopVm(Profile* profile,
return;
}
std::string owner_id = CryptohomeIdForProfile(profile);
vm_tools::concierge::StopVmRequest request;
request.set_owner_id(CryptohomeIdForProfile(profile));
request.set_name(std::move(name));
request.set_owner_id(owner_id);
request.set_name(name);
GetConciergeClient()->StopVm(
std::move(request),
base::BindOnce(&CrostiniManager::OnStopVm, weak_ptr_factory_.GetWeakPtr(),
std::move(owner_id), std::move(name),
std::move(callback)));
}
......@@ -920,6 +930,8 @@ void CrostiniManager::OnListVmDisks(
}
void CrostiniManager::OnStartTerminaVm(
std::string owner_id,
std::string vm_name,
StartTerminaVmCallback callback,
base::Optional<vm_tools::concierge::StartVmResponse> reply) {
if (!reply.has_value()) {
......@@ -934,10 +946,13 @@ void CrostiniManager::OnStartTerminaVm(
std::move(callback).Run(ConciergeClientResult::VM_START_FAILED);
return;
}
running_vms_.emplace(std::move(owner_id), std::move(vm_name));
std::move(callback).Run(ConciergeClientResult::SUCCESS);
}
void CrostiniManager::OnStopVm(
std::string owner_id,
std::string vm_name,
StopVmCallback callback,
base::Optional<vm_tools::concierge::StopVmResponse> reply) {
if (!reply.has_value()) {
......@@ -960,6 +975,8 @@ void CrostiniManager::OnStopVm(
return;
}
}
// Remove from running_vms_.
running_vms_.erase(std::make_pair(std::move(owner_id), std::move(vm_name)));
std::move(callback).Run(ConciergeClientResult::SUCCESS);
}
......
......@@ -6,6 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_
#include <map>
#include <set>
#include <string>
#include <tuple>
#include <utility>
......@@ -276,6 +277,8 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
// Returns the singleton instance of CrostiniManager.
static CrostiniManager* GetInstance();
bool IsVmRunning(Profile* profile, std::string vm_name);
private:
friend struct base::DefaultSingletonTraits<CrostiniManager>;
......@@ -303,12 +306,16 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
// Callback for ConciergeClient::StartTerminaVm. Called after the Concierge
// service method finishes.
void OnStartTerminaVm(
std::string owner_id,
std::string vm_name,
StartTerminaVmCallback callback,
base::Optional<vm_tools::concierge::StartVmResponse> reply);
// Callback for ConciergeClient::StopVm. Called after the Concierge
// service method finishes.
void OnStopVm(StopVmCallback callback,
void OnStopVm(std::string owner_id,
std::string vm_name,
StopVmCallback callback,
base::Optional<vm_tools::concierge::StopVmResponse> reply);
// Callback for CrostiniClient::StartConcierge. Called after the
......@@ -367,6 +374,9 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
ShutdownContainerCallback>
shutdown_container_callbacks_;
// Running vms as <owner_id, vm_name> pairs.
std::set<std::pair<std::string, std::string>> running_vms_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<CrostiniManager> weak_ptr_factory_;
......
......@@ -149,6 +149,11 @@ bool IsCrostiniEnabled(Profile* profile) {
return profile->GetPrefs()->GetBoolean(crostini::prefs::kCrostiniEnabled);
}
bool IsCrostiniRunning(Profile* profile) {
return crostini::CrostiniManager::GetInstance()->IsVmRunning(
profile, kCrostiniDefaultVmName);
}
void LaunchCrostiniApp(Profile* profile,
const std::string& app_id,
int64_t display_id) {
......
......@@ -32,6 +32,9 @@ bool IsCrostiniUIAllowedForProfile(Profile* profile);
// at least once and not deleted it.
bool IsCrostiniEnabled(Profile* profile);
// Returns whether the default Crostini VM is running for the user.
bool IsCrostiniRunning(Profile* profile);
// Launches the Crostini app with ID of |app_id| on the display with ID of
// |display_id|. |app_id| should be a valid Crostini app list id.
void LaunchCrostiniApp(Profile* profile,
......
......@@ -29,6 +29,8 @@ void CrostiniAppContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
AddContextMenuOption(menu_model, ash::UNINSTALL,
IDS_APP_LIST_UNINSTALL_ITEM);
AddContextMenuOption(menu_model, ash::MENU_CLOSE,
IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM);
}
}
......@@ -37,6 +39,10 @@ bool CrostiniAppContextMenu::IsCommandIdEnabled(int command_id) const {
if (app_id() == kCrostiniTerminalId) {
return IsCrostiniEnabled(profile());
}
} else if (command_id == ash::MENU_CLOSE) {
if (app_id() == kCrostiniTerminalId) {
return IsCrostiniRunning(profile());
}
}
return app_list::AppContextMenu::IsCommandIdEnabled(command_id);
}
......@@ -49,6 +55,14 @@ void CrostiniAppContextMenu::ExecuteCommand(int command_id, int event_flags) {
return;
}
break;
case ash::MENU_CLOSE:
if (app_id() == kCrostiniTerminalId) {
crostini::CrostiniManager::GetInstance()->StopVm(
profile(), kCrostiniDefaultVmName, base::DoNothing());
return;
}
break;
}
app_list::AppContextMenu::ExecuteCommand(command_id, event_flags);
}
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