terminal_private_api.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/extensions/api/terminal/terminal_private_api.h" 6 7#include "base/bind.h" 8#include "base/json/json_writer.h" 9#include "base/sys_info.h" 10#include "base/values.h" 11#include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h" 12#include "chrome/browser/extensions/extension_service.h" 13#include "chrome/browser/extensions/extension_system.h" 14#include "chrome/browser/profiles/profile.h" 15#include "chrome/common/extensions/api/terminal_private.h" 16#include "chromeos/process_proxy/process_proxy_registry.h" 17#include "content/public/browser/browser_thread.h" 18#include "extensions/browser/event_router.h" 19 20namespace terminal_private = extensions::api::terminal_private; 21namespace OnTerminalResize = 22 extensions::api::terminal_private::OnTerminalResize; 23namespace OpenTerminalProcess = 24 extensions::api::terminal_private::OpenTerminalProcess; 25namespace SendInput = extensions::api::terminal_private::SendInput; 26 27namespace { 28 29const char kCroshName[] = "crosh"; 30const char kCroshCommand[] = "/usr/bin/crosh"; 31// We make stubbed crosh just echo back input. 32const char kStubbedCroshCommand[] = "cat"; 33 34const char* GetCroshPath() { 35 if (base::SysInfo::IsRunningOnChromeOS()) 36 return kCroshCommand; 37 else 38 return kStubbedCroshCommand; 39} 40 41const char* GetProcessCommandForName(const std::string& name) { 42 if (name == kCroshName) 43 return GetCroshPath(); 44 else 45 return NULL; 46} 47 48void NotifyProcessOutput(Profile* profile, 49 const std::string& extension_id, 50 pid_t pid, 51 const std::string& output_type, 52 const std::string& output) { 53 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { 54 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 55 base::Bind(&NotifyProcessOutput, profile, extension_id, 56 pid, output_type, output)); 57 return; 58 } 59 60 scoped_ptr<base::ListValue> args(new base::ListValue()); 61 args->Append(new base::FundamentalValue(pid)); 62 args->Append(new base::StringValue(output_type)); 63 args->Append(new base::StringValue(output)); 64 65 if (profile && 66 extensions::ExtensionSystem::Get(profile)->event_router()) { 67 scoped_ptr<extensions::Event> event(new extensions::Event( 68 terminal_private::OnProcessOutput::kEventName, args.Pass())); 69 extensions::ExtensionSystem::Get(profile)->event_router()-> 70 DispatchEventToExtension(extension_id, event.Pass()); 71 } 72} 73 74} // namespace 75 76namespace extensions { 77 78TerminalPrivateFunction::TerminalPrivateFunction() {} 79 80TerminalPrivateFunction::~TerminalPrivateFunction() {} 81 82bool TerminalPrivateFunction::RunImpl() { 83 return RunTerminalFunction(); 84} 85 86TerminalPrivateOpenTerminalProcessFunction:: 87 TerminalPrivateOpenTerminalProcessFunction() : command_(NULL) {} 88 89TerminalPrivateOpenTerminalProcessFunction:: 90 ~TerminalPrivateOpenTerminalProcessFunction() {} 91 92bool TerminalPrivateOpenTerminalProcessFunction::RunTerminalFunction() { 93 scoped_ptr<OpenTerminalProcess::Params> params( 94 OpenTerminalProcess::Params::Create(*args_)); 95 EXTENSION_FUNCTION_VALIDATE(params.get()); 96 97 command_ = GetProcessCommandForName(params->process_name); 98 if (!command_) { 99 error_ = "Invalid process name."; 100 return false; 101 } 102 103 // Registry lives on FILE thread. 104 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 105 base::Bind(&TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread, 106 this)); 107 return true; 108} 109 110void TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread() { 111 DCHECK(command_); 112 113 chromeos::ProcessProxyRegistry* registry = 114 chromeos::ProcessProxyRegistry::Get(); 115 pid_t pid; 116 if (!registry->OpenProcess( 117 command_, 118 &pid, 119 base::Bind(&NotifyProcessOutput, GetProfile(), extension_id()))) { 120 // If new process could not be opened, we return -1. 121 pid = -1; 122 } 123 124 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 125 base::Bind(&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread, 126 this, pid)); 127} 128 129TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {} 130 131void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) { 132 SetResult(new base::FundamentalValue(pid)); 133 SendResponse(true); 134} 135 136bool TerminalPrivateSendInputFunction::RunTerminalFunction() { 137 scoped_ptr<SendInput::Params> params(SendInput::Params::Create(*args_)); 138 EXTENSION_FUNCTION_VALIDATE(params.get()); 139 140 // Registry lives on the FILE thread. 141 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 142 base::Bind(&TerminalPrivateSendInputFunction::SendInputOnFileThread, 143 this, params->pid, params->input)); 144 return true; 145} 146 147void TerminalPrivateSendInputFunction::SendInputOnFileThread(pid_t pid, 148 const std::string& text) { 149 bool success = chromeos::ProcessProxyRegistry::Get()->SendInput(pid, text); 150 151 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 152 base::Bind(&TerminalPrivateSendInputFunction::RespondOnUIThread, this, 153 success)); 154} 155 156void TerminalPrivateSendInputFunction::RespondOnUIThread(bool success) { 157 SetResult(new base::FundamentalValue(success)); 158 SendResponse(true); 159} 160 161TerminalPrivateCloseTerminalProcessFunction:: 162 ~TerminalPrivateCloseTerminalProcessFunction() {} 163 164bool TerminalPrivateCloseTerminalProcessFunction::RunTerminalFunction() { 165 if (args_->GetSize() != 1) 166 return false; 167 pid_t pid; 168 if (!args_->GetInteger(0, &pid)) 169 return false; 170 171 // Registry lives on the FILE thread. 172 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 173 base::Bind(&TerminalPrivateCloseTerminalProcessFunction:: 174 CloseOnFileThread, this, pid)); 175 176 return true; 177} 178 179void TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread(pid_t pid) { 180 bool success = chromeos::ProcessProxyRegistry::Get()->CloseProcess(pid); 181 182 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 183 base::Bind(&TerminalPrivateCloseTerminalProcessFunction:: 184 RespondOnUIThread, this, success)); 185} 186 187void TerminalPrivateCloseTerminalProcessFunction::RespondOnUIThread( 188 bool success) { 189 SetResult(new base::FundamentalValue(success)); 190 SendResponse(true); 191} 192 193TerminalPrivateOnTerminalResizeFunction:: 194 ~TerminalPrivateOnTerminalResizeFunction() {} 195 196bool TerminalPrivateOnTerminalResizeFunction::RunTerminalFunction() { 197 scoped_ptr<OnTerminalResize::Params> params( 198 OnTerminalResize::Params::Create(*args_)); 199 EXTENSION_FUNCTION_VALIDATE(params.get()); 200 201 // Registry lives on the FILE thread. 202 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 203 base::Bind(&TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread, 204 this, params->pid, params->width, params->height)); 205 206 return true; 207} 208 209void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread(pid_t pid, 210 int width, int height) { 211 bool success = chromeos::ProcessProxyRegistry::Get()->OnTerminalResize( 212 pid, width, height); 213 214 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 215 base::Bind(&TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread, 216 this, success)); 217} 218 219void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) { 220 SetResult(new base::FundamentalValue(success)); 221 SendResponse(true); 222} 223 224} // namespace extensions 225