Commit 4fc642b3 authored by Joel Hockey's avatar Joel Hockey Committed by Commit Bot

Track last active terminal in TerminalPrivateAPI and use for vsh

Keep track of the last active terminal by capturing terminal_id
sent from the web app.  When a new process is opened, we call
cicerone GetVshSession to find the container shell pid to set for cwd.

Bug: 1113207
Change-Id: Ia6ff0eb43b9bcefa781f19d141b36143cfd48649
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2351644Reviewed-by: default avatarJason Lin <lxj@google.com>
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799003}
parent 356964bd
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/api/terminal/terminal_private_api.h" #include "chrome/browser/extensions/api/terminal/terminal_private_api.h"
#include <cstdlib>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/values.h" #include "base/values.h"
...@@ -71,16 +73,20 @@ const char kSwitchTargetContainer[] = "target_container"; ...@@ -71,16 +73,20 @@ const char kSwitchTargetContainer[] = "target_container";
const char kSwitchStartupId[] = "startup_id"; const char kSwitchStartupId[] = "startup_id";
const char kSwitchCurrentWorkingDir[] = "cwd"; const char kSwitchCurrentWorkingDir[] = "cwd";
int32_t g_last_active_pid = 0;
// Copies the value of |switch_name| if present from |src| to |dst|. If not // Copies the value of |switch_name| if present from |src| to |dst|. If not
// present, uses |default_value|. Returns the value set into |dst|. // present, uses |default_value| if nonempty. Returns the value set into |dst|.
std::string GetSwitch(const base::CommandLine* src, std::string GetSwitch(const base::CommandLine& src,
base::CommandLine* dst, base::CommandLine* dst,
const std::string& switch_name, const std::string& switch_name,
const std::string& default_value) { const std::string& default_value) {
std::string result = src->HasSwitch(switch_name) std::string result = src.HasSwitch(switch_name)
? src->GetSwitchValueASCII(switch_name) ? src.GetSwitchValueASCII(switch_name)
: default_value; : default_value;
dst->AppendSwitchASCII(switch_name, result); if (!result.empty()) {
dst->AppendSwitchASCII(switch_name, result);
}
return result; return result;
} }
...@@ -138,6 +144,12 @@ void PreferenceChanged(Profile* profile, ...@@ -138,6 +144,12 @@ void PreferenceChanged(Profile* profile,
} }
} }
void SetLastActiveTerminal(const std::string& terminal_id) {
// The terminal_id is <pid>-<guid>. We will parse it to get the pid.
// atoi will read all leading digits and stop at any non-digit such as '-'.
g_last_active_pid = atoi(terminal_id.c_str());
}
} // namespace } // namespace
namespace extensions { namespace extensions {
...@@ -214,15 +226,19 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess( ...@@ -214,15 +226,19 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess(
// Passing --crosh-command overrides any JS process name. // Passing --crosh-command overrides any JS process name.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kCroshCommand)) { if (command_line->HasSwitch(switches::kCroshCommand)) {
OpenProcess(user_id_hash, tab_id, OpenProcess(
{command_line->GetSwitchValueASCII(switches::kCroshCommand)}); user_id_hash, tab_id,
base::CommandLine(base::FilePath(
command_line->GetSwitchValueASCII(switches::kCroshCommand))));
} else if (process_name == kCroshName) { } else if (process_name == kCroshName) {
// command=crosh: use '/usr/bin/crosh' on a device, 'cat' otherwise. // command=crosh: use '/usr/bin/crosh' on a device, 'cat' otherwise.
if (base::SysInfo::IsRunningOnChromeOS()) { if (base::SysInfo::IsRunningOnChromeOS()) {
OpenProcess(user_id_hash, tab_id, {kCroshCommand}); OpenProcess(user_id_hash, tab_id,
base::CommandLine(base::FilePath(kCroshCommand)));
} else { } else {
OpenProcess(user_id_hash, tab_id, {kStubbedCroshCommand}); OpenProcess(user_id_hash, tab_id,
base::CommandLine(base::FilePath(kStubbedCroshCommand)));
} }
} else if (process_name == kVmShellName) { } else if (process_name == kVmShellName) {
...@@ -233,19 +249,19 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess( ...@@ -233,19 +249,19 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess(
// command=vmshell: ensure --owner_id, --vm_name, --target_container, --cwd // command=vmshell: ensure --owner_id, --vm_name, --target_container, --cwd
// are set, and the specified vm/container is running. // are set, and the specified vm/container is running.
base::CommandLine vmshell_cmd({kVmShellCommand}); base::CommandLine cmdline((base::FilePath(kVmShellCommand)));
if (!args) if (!args)
args = std::make_unique<std::vector<std::string>>(); args = std::make_unique<std::vector<std::string>>();
args->insert(args->begin(), kVmShellCommand); args->insert(args->begin(), kVmShellCommand);
base::CommandLine params_args(*args); base::CommandLine params_args(*args);
std::string owner_id = std::string owner_id =
GetSwitch(&params_args, &vmshell_cmd, kSwitchOwnerId, user_id_hash); GetSwitch(params_args, &cmdline, kSwitchOwnerId, user_id_hash);
std::string vm_name = GetSwitch(&params_args, &vmshell_cmd, kSwitchVmName, std::string vm_name = GetSwitch(params_args, &cmdline, kSwitchVmName,
crostini::kCrostiniDefaultVmName); crostini::kCrostiniDefaultVmName);
std::string container_name = std::string container_name =
GetSwitch(&params_args, &vmshell_cmd, kSwitchTargetContainer, GetSwitch(params_args, &cmdline, kSwitchTargetContainer,
crostini::kCrostiniDefaultContainerName); crostini::kCrostiniDefaultContainerName);
GetSwitch(&params_args, &vmshell_cmd, kSwitchCurrentWorkingDir, ""); GetSwitch(params_args, &cmdline, kSwitchCurrentWorkingDir, "");
std::string startup_id = params_args.GetSwitchValueASCII(kSwitchStartupId); std::string startup_id = params_args.GetSwitchValueASCII(kSwitchStartupId);
crostini::ContainerId container_id(vm_name, container_name); crostini::ContainerId container_id(vm_name, container_name);
...@@ -265,7 +281,7 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess( ...@@ -265,7 +281,7 @@ TerminalPrivateOpenTerminalProcessFunction::OpenProcess(
base::BindOnce( base::BindOnce(
&TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted, &TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted,
this, std::move(observer), user_id_hash, tab_id, this, std::move(observer), user_id_hash, tab_id,
vmshell_cmd.argv()), std::move(cmdline)),
observer_ptr); observer_ptr);
} else { } else {
// command=[unrecognized]. // command=[unrecognized].
...@@ -278,7 +294,7 @@ void TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted( ...@@ -278,7 +294,7 @@ void TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted(
std::unique_ptr<CrostiniStartupStatus> startup_status, std::unique_ptr<CrostiniStartupStatus> startup_status,
const std::string& user_id_hash, const std::string& user_id_hash,
int tab_id, int tab_id,
const std::vector<std::string>& arguments, base::CommandLine cmdline,
crostini::CrostiniResult result) { crostini::CrostiniResult result) {
if (crostini::MaybeShowCrostiniDialogBeforeLaunch( if (crostini::MaybeShowCrostiniDialogBeforeLaunch(
Profile::FromBrowserContext(browser_context()), result)) { Profile::FromBrowserContext(browser_context()), result)) {
...@@ -289,7 +305,7 @@ void TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted( ...@@ -289,7 +305,7 @@ void TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted(
} }
startup_status->OnCrostiniRestarted(result); startup_status->OnCrostiniRestarted(result);
if (result == crostini::CrostiniResult::SUCCESS) { if (result == crostini::CrostiniResult::SUCCESS) {
OpenProcess(user_id_hash, tab_id, arguments); OpenVmshellProcess(user_id_hash, tab_id, std::move(cmdline));
} else { } else {
const std::string msg = const std::string msg =
base::StringPrintf("Error starting crostini for terminal: %d", result); base::StringPrintf("Error starting crostini for terminal: %d", result);
...@@ -298,11 +314,49 @@ void TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted( ...@@ -298,11 +314,49 @@ void TerminalPrivateOpenTerminalProcessFunction::OnCrostiniRestarted(
} }
} }
void TerminalPrivateOpenTerminalProcessFunction::OpenVmshellProcess(
const std::string& user_id_hash,
int tab_id,
base::CommandLine cmdline) {
// If cwd is already set in cmdline, or this is the first terminal, open now.
if (cmdline.HasSwitch(kSwitchCurrentWorkingDir) || !g_last_active_pid) {
return OpenProcess(user_id_hash, tab_id, std::move(cmdline));
}
// Lookup container shell pid from cicierone to use for cwd.
crostini::CrostiniManager::GetForProfile(
Profile::FromBrowserContext(browser_context()))
->GetVshSession(
crostini::ContainerId::GetDefault(), g_last_active_pid,
base::BindOnce(
&TerminalPrivateOpenTerminalProcessFunction::OnGetVshSession,
this, user_id_hash, tab_id, std::move(cmdline),
g_last_active_pid));
}
void TerminalPrivateOpenTerminalProcessFunction::OnGetVshSession(
const std::string& user_id_hash,
int tab_id,
base::CommandLine cmdline,
int32_t vsh_pid,
bool success,
const std::string& failure_reason,
int32_t container_shell_pid) {
if (!success) {
LOG(WARNING) << "Failed to get vsh session for " << vsh_pid << ". "
<< failure_reason;
} else {
cmdline.AppendSwitchASCII(kSwitchCurrentWorkingDir,
base::NumberToString(container_shell_pid));
}
OpenProcess(user_id_hash, tab_id, std::move(cmdline));
}
void TerminalPrivateOpenTerminalProcessFunction::OpenProcess( void TerminalPrivateOpenTerminalProcessFunction::OpenProcess(
const std::string& user_id_hash, const std::string& user_id_hash,
int tab_id, int tab_id,
const std::vector<std::string>& arguments) { base::CommandLine cmdline) {
DCHECK(!arguments.empty()); DCHECK(!cmdline.argv().empty());
// Registry lives on its own task runner. // Registry lives on its own task runner.
chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask( chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask(
FROM_HERE, FROM_HERE,
...@@ -312,25 +366,35 @@ void TerminalPrivateOpenTerminalProcessFunction::OpenProcess( ...@@ -312,25 +366,35 @@ void TerminalPrivateOpenTerminalProcessFunction::OpenProcess(
base::Bind( base::Bind(
&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread, &TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread,
this), this),
arguments, user_id_hash)); std::move(cmdline), user_id_hash));
} }
void TerminalPrivateOpenTerminalProcessFunction::OpenOnRegistryTaskRunner( void TerminalPrivateOpenTerminalProcessFunction::OpenOnRegistryTaskRunner(
const ProcessOutputCallback& output_callback, const ProcessOutputCallback& output_callback,
const OpenProcessCallback& callback, const OpenProcessCallback& callback,
const std::vector<std::string>& arguments, base::CommandLine cmdline,
const std::string& user_id_hash) { const std::string& user_id_hash) {
chromeos::ProcessProxyRegistry* registry = chromeos::ProcessProxyRegistry* registry =
chromeos::ProcessProxyRegistry::Get(); chromeos::ProcessProxyRegistry::Get();
const base::CommandLine cmdline{arguments};
std::string terminal_id; std::string terminal_id;
bool success = registry->OpenProcess(cmdline, user_id_hash, output_callback, bool success = registry->OpenProcess(std::move(cmdline), user_id_hash,
&terminal_id); output_callback, &terminal_id);
content::GetUIThreadTaskRunner({})->PostTask( content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(callback, success, terminal_id)); FROM_HERE, base::BindOnce(callback, success, terminal_id));
} }
void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(
bool success,
const std::string& terminal_id) {
if (!success) {
Respond(Error("Failed to open process."));
return;
}
SetLastActiveTerminal(terminal_id);
Respond(OneArgument(std::make_unique<base::Value>(terminal_id)));
}
TerminalPrivateOpenVmshellProcessFunction:: TerminalPrivateOpenVmshellProcessFunction::
~TerminalPrivateOpenVmshellProcessFunction() = default; ~TerminalPrivateOpenVmshellProcessFunction() = default;
...@@ -346,19 +410,10 @@ TerminalPrivateOpenVmshellProcessFunction::Run() { ...@@ -346,19 +410,10 @@ TerminalPrivateOpenVmshellProcessFunction::Run() {
TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() = default; TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() = default;
void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(
bool success,
const std::string& terminal_id) {
if (!success) {
Respond(Error("Failed to open process."));
return;
}
Respond(OneArgument(std::make_unique<base::Value>(terminal_id)));
}
ExtensionFunction::ResponseAction TerminalPrivateSendInputFunction::Run() { ExtensionFunction::ResponseAction TerminalPrivateSendInputFunction::Run() {
std::unique_ptr<SendInput::Params> params(SendInput::Params::Create(*args_)); std::unique_ptr<SendInput::Params> params(SendInput::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get()); EXTENSION_FUNCTION_VALIDATE(params.get());
SetLastActiveTerminal(params->id);
// Registry lives on its own task runner. // Registry lives on its own task runner.
chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask( chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask(
...@@ -428,6 +483,7 @@ TerminalPrivateOnTerminalResizeFunction::Run() { ...@@ -428,6 +483,7 @@ TerminalPrivateOnTerminalResizeFunction::Run() {
std::unique_ptr<OnTerminalResize::Params> params( std::unique_ptr<OnTerminalResize::Params> params(
OnTerminalResize::Params::Create(*args_)); OnTerminalResize::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get()); EXTENSION_FUNCTION_VALIDATE(params.get());
SetLastActiveTerminal(params->id);
// Registry lives on its own task runner. // Registry lives on its own task runner.
chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask( chromeos::ProcessProxyRegistry::GetTaskRunner()->PostTask(
......
...@@ -59,27 +59,38 @@ class TerminalPrivateOpenTerminalProcessFunction : public ExtensionFunction { ...@@ -59,27 +59,38 @@ class TerminalPrivateOpenTerminalProcessFunction : public ExtensionFunction {
std::unique_ptr<std::vector<std::string>> args); std::unique_ptr<std::vector<std::string>> args);
private: private:
// Callback for when starting crostini is complete.
void OnCrostiniRestarted( void OnCrostiniRestarted(
std::unique_ptr<CrostiniStartupStatus> startup_status, std::unique_ptr<CrostiniStartupStatus> startup_status,
const std::string& user_id_hash, const std::string& user_id_hash,
int tab_id, int tab_id,
const std::vector<std::string>& arguments, base::CommandLine cmdline,
crostini::CrostiniResult result); crostini::CrostiniResult result);
void OpenVmshellProcess(const std::string& user_id_hash,
int tab_id,
base::CommandLine cmdline);
void OnGetVshSession(const std::string& user_id_hash,
int tab_id,
base::CommandLine cmdline,
int32_t vsh_pid,
bool success,
const std::string& failure_reason,
int32_t container_shell_pid);
void OpenProcess(const std::string& user_id_hash,
int tab_id,
base::CommandLine cmdline);
using ProcessOutputCallback = using ProcessOutputCallback =
base::Callback<void(const std::string& terminal_id, base::Callback<void(const std::string& terminal_id,
const std::string& output_type, const std::string& output_type,
const std::string& output)>; const std::string& output)>;
using OpenProcessCallback = using OpenProcessCallback =
base::Callback<void(bool success, const std::string& terminal_id)>; base::Callback<void(bool success, const std::string& terminal_id)>;
void OpenProcess(const std::string& user_id_hash,
int tab_id,
const std::vector<std::string>& arguments);
void OpenOnRegistryTaskRunner(const ProcessOutputCallback& output_callback, void OpenOnRegistryTaskRunner(const ProcessOutputCallback& output_callback,
const OpenProcessCallback& callback, const OpenProcessCallback& callback,
const std::vector<std::string>& arguments, base::CommandLine cmdline,
const std::string& user_id_hash); const std::string& user_id_hash);
void RespondOnUIThread(bool success, const std::string& terminal_id); void RespondOnUIThread(bool success, const std::string& terminal_id);
}; };
......
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