terminal_private_api.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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/chromeos/chromeos_version.h" 9#include "base/json/json_writer.h" 10#include "base/values.h" 11#include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h" 12#include "chrome/browser/extensions/event_router.h" 13#include "chrome/browser/extensions/extension_service.h" 14#include "chrome/browser/extensions/extension_system.h" 15#include "chrome/browser/profiles/profile.h" 16#include "chrome/common/extensions/api/terminal_private.h" 17#include "chromeos/process_proxy/process_proxy_registry.h" 18#include "content/public/browser/browser_thread.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::chromeos::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_, &pid, 118 base::Bind(&NotifyProcessOutput, profile_, extension_id()))) { 119 // If new process could not be opened, we return -1. 120 pid = -1; 121 } 122 123 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 124 base::Bind(&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread, 125 this, pid)); 126} 127 128TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {} 129 130void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) { 131 SetResult(new base::FundamentalValue(pid)); 132 SendResponse(true); 133} 134 135bool TerminalPrivateSendInputFunction::RunTerminalFunction() { 136 scoped_ptr<SendInput::Params> params(SendInput::Params::Create(*args_)); 137 EXTENSION_FUNCTION_VALIDATE(params.get()); 138 139 // Registry lives on the FILE thread. 140 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 141 base::Bind(&TerminalPrivateSendInputFunction::SendInputOnFileThread, 142 this, params->pid, params->input)); 143 return true; 144} 145 146void TerminalPrivateSendInputFunction::SendInputOnFileThread(pid_t pid, 147 const std::string& text) { 148 bool success = chromeos::ProcessProxyRegistry::Get()->SendInput(pid, text); 149 150 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 151 base::Bind(&TerminalPrivateSendInputFunction::RespondOnUIThread, this, 152 success)); 153} 154 155void TerminalPrivateSendInputFunction::RespondOnUIThread(bool success) { 156 SetResult(new base::FundamentalValue(success)); 157 SendResponse(true); 158} 159 160TerminalPrivateCloseTerminalProcessFunction:: 161 ~TerminalPrivateCloseTerminalProcessFunction() {} 162 163bool TerminalPrivateCloseTerminalProcessFunction::RunTerminalFunction() { 164 if (args_->GetSize() != 1) 165 return false; 166 pid_t pid; 167 if (!args_->GetInteger(0, &pid)) 168 return false; 169 170 // Registry lives on the FILE thread. 171 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 172 base::Bind(&TerminalPrivateCloseTerminalProcessFunction:: 173 CloseOnFileThread, this, pid)); 174 175 return true; 176} 177 178void TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread(pid_t pid) { 179 bool success = chromeos::ProcessProxyRegistry::Get()->CloseProcess(pid); 180 181 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 182 base::Bind(&TerminalPrivateCloseTerminalProcessFunction:: 183 RespondOnUIThread, this, success)); 184} 185 186void TerminalPrivateCloseTerminalProcessFunction::RespondOnUIThread( 187 bool success) { 188 SetResult(new base::FundamentalValue(success)); 189 SendResponse(true); 190} 191 192TerminalPrivateOnTerminalResizeFunction:: 193 ~TerminalPrivateOnTerminalResizeFunction() {} 194 195bool TerminalPrivateOnTerminalResizeFunction::RunTerminalFunction() { 196 scoped_ptr<OnTerminalResize::Params> params( 197 OnTerminalResize::Params::Create(*args_)); 198 EXTENSION_FUNCTION_VALIDATE(params.get()); 199 200 // Registry lives on the FILE thread. 201 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 202 base::Bind(&TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread, 203 this, params->pid, params->width, params->height)); 204 205 return true; 206} 207 208void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread(pid_t pid, 209 int width, int height) { 210 bool success = chromeos::ProcessProxyRegistry::Get()->OnTerminalResize( 211 pid, width, height); 212 213 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 214 base::Bind(&TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread, 215 this, success)); 216} 217 218void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) { 219 SetResult(new base::FundamentalValue(success)); 220 SendResponse(true); 221} 222 223} // namespace extensions 224