blob: faeb3b5b201a2d18a7f48f82cc292bb149ab190e [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/terminal/terminal_private_api.h"
#include "base/bind.h"
#include "base/json/json_writer.h"
#include "base/sys_info.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/terminal_private.h"
#include "chromeos/process_proxy/process_proxy_registry.h"
#include "content/public/browser/browser_thread.h"
namespace terminal_private = extensions::api::terminal_private;
namespace OnTerminalResize =
extensions::api::terminal_private::OnTerminalResize;
namespace OpenTerminalProcess =
extensions::api::terminal_private::OpenTerminalProcess;
namespace SendInput = extensions::api::terminal_private::SendInput;
namespace {
const char kCroshName[] = "crosh";
const char kCroshCommand[] = "/usr/bin/crosh";
// We make stubbed crosh just echo back input.
const char kStubbedCroshCommand[] = "cat";
const char* GetCroshPath() {
if (base::SysInfo::IsRunningOnChromeOS())
return kCroshCommand;
else
return kStubbedCroshCommand;
}
const char* GetProcessCommandForName(const std::string& name) {
if (name == kCroshName)
return GetCroshPath();
else
return NULL;
}
void NotifyProcessOutput(Profile* profile,
const std::string& extension_id,
pid_t pid,
const std::string& output_type,
const std::string& output) {
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&NotifyProcessOutput, profile, extension_id,
pid, output_type, output));
return;
}
scoped_ptr<base::ListValue> args(new base::ListValue());
args->Append(new base::FundamentalValue(pid));
args->Append(new base::StringValue(output_type));
args->Append(new base::StringValue(output));
if (profile &&
extensions::ExtensionSystem::Get(profile)->event_router()) {
scoped_ptr<extensions::Event> event(new extensions::Event(
terminal_private::OnProcessOutput::kEventName, args.Pass()));
extensions::ExtensionSystem::Get(profile)->event_router()->
DispatchEventToExtension(extension_id, event.Pass());
}
}
} // namespace
namespace extensions {
TerminalPrivateFunction::TerminalPrivateFunction() {}
TerminalPrivateFunction::~TerminalPrivateFunction() {}
bool TerminalPrivateFunction::RunImpl() {
return RunTerminalFunction();
}
TerminalPrivateOpenTerminalProcessFunction::
TerminalPrivateOpenTerminalProcessFunction() : command_(NULL) {}
TerminalPrivateOpenTerminalProcessFunction::
~TerminalPrivateOpenTerminalProcessFunction() {}
bool TerminalPrivateOpenTerminalProcessFunction::RunTerminalFunction() {
scoped_ptr<OpenTerminalProcess::Params> params(
OpenTerminalProcess::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
command_ = GetProcessCommandForName(params->process_name);
if (!command_) {
error_ = "Invalid process name.";
return false;
}
// Registry lives on FILE thread.
content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
base::Bind(&TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread,
this));
return true;
}
void TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread() {
DCHECK(command_);
chromeos::ProcessProxyRegistry* registry =
chromeos::ProcessProxyRegistry::Get();
pid_t pid;
if (!registry->OpenProcess(
command_, &pid,
base::Bind(&NotifyProcessOutput, profile_, extension_id()))) {
// If new process could not be opened, we return -1.
pid = -1;
}
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread,
this, pid));
}
TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {}
void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) {
SetResult(new base::FundamentalValue(pid));
SendResponse(true);
}
bool TerminalPrivateSendInputFunction::RunTerminalFunction() {
scoped_ptr<SendInput::Params> params(SendInput::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
// Registry lives on the FILE thread.
content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
base::Bind(&TerminalPrivateSendInputFunction::SendInputOnFileThread,
this, params->pid, params->input));
return true;
}
void TerminalPrivateSendInputFunction::SendInputOnFileThread(pid_t pid,
const std::string& text) {
bool success = chromeos::ProcessProxyRegistry::Get()->SendInput(pid, text);
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&TerminalPrivateSendInputFunction::RespondOnUIThread, this,
success));
}
void TerminalPrivateSendInputFunction::RespondOnUIThread(bool success) {
SetResult(new base::FundamentalValue(success));
SendResponse(true);
}
TerminalPrivateCloseTerminalProcessFunction::
~TerminalPrivateCloseTerminalProcessFunction() {}
bool TerminalPrivateCloseTerminalProcessFunction::RunTerminalFunction() {
if (args_->GetSize() != 1)
return false;
pid_t pid;
if (!args_->GetInteger(0, &pid))
return false;
// Registry lives on the FILE thread.
content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
base::Bind(&TerminalPrivateCloseTerminalProcessFunction::
CloseOnFileThread, this, pid));
return true;
}
void TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread(pid_t pid) {
bool success = chromeos::ProcessProxyRegistry::Get()->CloseProcess(pid);
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&TerminalPrivateCloseTerminalProcessFunction::
RespondOnUIThread, this, success));
}
void TerminalPrivateCloseTerminalProcessFunction::RespondOnUIThread(
bool success) {
SetResult(new base::FundamentalValue(success));
SendResponse(true);
}
TerminalPrivateOnTerminalResizeFunction::
~TerminalPrivateOnTerminalResizeFunction() {}
bool TerminalPrivateOnTerminalResizeFunction::RunTerminalFunction() {
scoped_ptr<OnTerminalResize::Params> params(
OnTerminalResize::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
// Registry lives on the FILE thread.
content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
base::Bind(&TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread,
this, params->pid, params->width, params->height));
return true;
}
void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread(pid_t pid,
int width, int height) {
bool success = chromeos::ProcessProxyRegistry::Get()->OnTerminalResize(
pid, width, height);
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread,
this, success));
}
void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) {
SetResult(new base::FundamentalValue(success));
SendResponse(true);
}
} // namespace extensions