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 ...@@ -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."> <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. Error uninstalling Linux. Please try again.
</message> </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 --> <!-- 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."> <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() { ...@@ -414,6 +414,12 @@ CrostiniManager* CrostiniManager::GetInstance() {
return base::Singleton<CrostiniManager>::get(); 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) { CrostiniManager::CrostiniManager() : weak_ptr_factory_(this) {
// Cicerone/ConciergeClient and its observer_list_ will be destroyed together. // 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 // 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, ...@@ -632,7 +638,8 @@ void CrostiniManager::StartTerminaVm(std::string owner_id,
GetConciergeClient()->StartTerminaVm( GetConciergeClient()->StartTerminaVm(
request, request,
base::BindOnce(&CrostiniManager::OnStartTerminaVm, 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, void CrostiniManager::StopVm(Profile* profile,
...@@ -644,13 +651,16 @@ void CrostiniManager::StopVm(Profile* profile, ...@@ -644,13 +651,16 @@ void CrostiniManager::StopVm(Profile* profile,
return; return;
} }
std::string owner_id = CryptohomeIdForProfile(profile);
vm_tools::concierge::StopVmRequest request; vm_tools::concierge::StopVmRequest request;
request.set_owner_id(CryptohomeIdForProfile(profile)); request.set_owner_id(owner_id);
request.set_name(std::move(name)); request.set_name(name);
GetConciergeClient()->StopVm( GetConciergeClient()->StopVm(
std::move(request), std::move(request),
base::BindOnce(&CrostiniManager::OnStopVm, weak_ptr_factory_.GetWeakPtr(), base::BindOnce(&CrostiniManager::OnStopVm, weak_ptr_factory_.GetWeakPtr(),
std::move(owner_id), std::move(name),
std::move(callback))); std::move(callback)));
} }
...@@ -920,6 +930,8 @@ void CrostiniManager::OnListVmDisks( ...@@ -920,6 +930,8 @@ void CrostiniManager::OnListVmDisks(
} }
void CrostiniManager::OnStartTerminaVm( void CrostiniManager::OnStartTerminaVm(
std::string owner_id,
std::string vm_name,
StartTerminaVmCallback callback, StartTerminaVmCallback callback,
base::Optional<vm_tools::concierge::StartVmResponse> reply) { base::Optional<vm_tools::concierge::StartVmResponse> reply) {
if (!reply.has_value()) { if (!reply.has_value()) {
...@@ -934,10 +946,13 @@ void CrostiniManager::OnStartTerminaVm( ...@@ -934,10 +946,13 @@ void CrostiniManager::OnStartTerminaVm(
std::move(callback).Run(ConciergeClientResult::VM_START_FAILED); std::move(callback).Run(ConciergeClientResult::VM_START_FAILED);
return; return;
} }
running_vms_.emplace(std::move(owner_id), std::move(vm_name));
std::move(callback).Run(ConciergeClientResult::SUCCESS); std::move(callback).Run(ConciergeClientResult::SUCCESS);
} }
void CrostiniManager::OnStopVm( void CrostiniManager::OnStopVm(
std::string owner_id,
std::string vm_name,
StopVmCallback callback, StopVmCallback callback,
base::Optional<vm_tools::concierge::StopVmResponse> reply) { base::Optional<vm_tools::concierge::StopVmResponse> reply) {
if (!reply.has_value()) { if (!reply.has_value()) {
...@@ -960,6 +975,8 @@ void CrostiniManager::OnStopVm( ...@@ -960,6 +975,8 @@ void CrostiniManager::OnStopVm(
return; 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); std::move(callback).Run(ConciergeClientResult::SUCCESS);
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_ #define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_
#include <map> #include <map>
#include <set>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
...@@ -276,6 +277,8 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer, ...@@ -276,6 +277,8 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
// Returns the singleton instance of CrostiniManager. // Returns the singleton instance of CrostiniManager.
static CrostiniManager* GetInstance(); static CrostiniManager* GetInstance();
bool IsVmRunning(Profile* profile, std::string vm_name);
private: private:
friend struct base::DefaultSingletonTraits<CrostiniManager>; friend struct base::DefaultSingletonTraits<CrostiniManager>;
...@@ -303,12 +306,16 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer, ...@@ -303,12 +306,16 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
// Callback for ConciergeClient::StartTerminaVm. Called after the Concierge // Callback for ConciergeClient::StartTerminaVm. Called after the Concierge
// service method finishes. // service method finishes.
void OnStartTerminaVm( void OnStartTerminaVm(
std::string owner_id,
std::string vm_name,
StartTerminaVmCallback callback, StartTerminaVmCallback callback,
base::Optional<vm_tools::concierge::StartVmResponse> reply); base::Optional<vm_tools::concierge::StartVmResponse> reply);
// Callback for ConciergeClient::StopVm. Called after the Concierge // Callback for ConciergeClient::StopVm. Called after the Concierge
// service method finishes. // 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); base::Optional<vm_tools::concierge::StopVmResponse> reply);
// Callback for CrostiniClient::StartConcierge. Called after the // Callback for CrostiniClient::StartConcierge. Called after the
...@@ -367,6 +374,9 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer, ...@@ -367,6 +374,9 @@ class CrostiniManager : public chromeos::ConciergeClient::Observer,
ShutdownContainerCallback> ShutdownContainerCallback>
shutdown_container_callbacks_; 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 // Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed. // invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<CrostiniManager> weak_ptr_factory_; base::WeakPtrFactory<CrostiniManager> weak_ptr_factory_;
......
...@@ -149,6 +149,11 @@ bool IsCrostiniEnabled(Profile* profile) { ...@@ -149,6 +149,11 @@ bool IsCrostiniEnabled(Profile* profile) {
return profile->GetPrefs()->GetBoolean(crostini::prefs::kCrostiniEnabled); return profile->GetPrefs()->GetBoolean(crostini::prefs::kCrostiniEnabled);
} }
bool IsCrostiniRunning(Profile* profile) {
return crostini::CrostiniManager::GetInstance()->IsVmRunning(
profile, kCrostiniDefaultVmName);
}
void LaunchCrostiniApp(Profile* profile, void LaunchCrostiniApp(Profile* profile,
const std::string& app_id, const std::string& app_id,
int64_t display_id) { int64_t display_id) {
......
...@@ -32,6 +32,9 @@ bool IsCrostiniUIAllowedForProfile(Profile* profile); ...@@ -32,6 +32,9 @@ bool IsCrostiniUIAllowedForProfile(Profile* profile);
// at least once and not deleted it. // at least once and not deleted it.
bool IsCrostiniEnabled(Profile* profile); 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 // 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. // |display_id|. |app_id| should be a valid Crostini app list id.
void LaunchCrostiniApp(Profile* profile, void LaunchCrostiniApp(Profile* profile,
......
...@@ -29,6 +29,8 @@ void CrostiniAppContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) { ...@@ -29,6 +29,8 @@ void CrostiniAppContextMenu::BuildMenu(ui::SimpleMenuModel* menu_model) {
AddContextMenuOption(menu_model, ash::UNINSTALL, AddContextMenuOption(menu_model, ash::UNINSTALL,
IDS_APP_LIST_UNINSTALL_ITEM); 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 { ...@@ -37,6 +39,10 @@ bool CrostiniAppContextMenu::IsCommandIdEnabled(int command_id) const {
if (app_id() == kCrostiniTerminalId) { if (app_id() == kCrostiniTerminalId) {
return IsCrostiniEnabled(profile()); return IsCrostiniEnabled(profile());
} }
} else if (command_id == ash::MENU_CLOSE) {
if (app_id() == kCrostiniTerminalId) {
return IsCrostiniRunning(profile());
}
} }
return app_list::AppContextMenu::IsCommandIdEnabled(command_id); return app_list::AppContextMenu::IsCommandIdEnabled(command_id);
} }
...@@ -49,6 +55,14 @@ void CrostiniAppContextMenu::ExecuteCommand(int command_id, int event_flags) { ...@@ -49,6 +55,14 @@ void CrostiniAppContextMenu::ExecuteCommand(int command_id, int event_flags) {
return; return;
} }
break; 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); 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