terminal_private_api.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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_names.h" 13#include "chrome/browser/extensions/event_router.h" 14#include "chrome/browser/extensions/extension_service.h" 15#include "chrome/browser/extensions/extension_system.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/common/extensions/api/terminal_private.h" 18#include "chromeos/process_proxy/process_proxy_registry.h" 19#include "content/public/browser/browser_thread.h" 20 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 extensions::event_names::kOnTerminalProcessOutput, args.Pass())); 69 extensions::ExtensionSystem::Get(profile)->event_router()-> 70 DispatchEventToExtension(extension_id, event.Pass()); 71 } 72} 73 74} // namespace 75 76TerminalPrivateFunction::TerminalPrivateFunction() {} 77 78TerminalPrivateFunction::~TerminalPrivateFunction() {} 79 80bool TerminalPrivateFunction::RunImpl() { 81 return RunTerminalFunction(); 82} 83 84TerminalPrivateOpenTerminalProcessFunction:: 85 TerminalPrivateOpenTerminalProcessFunction() : command_(NULL) {} 86 87TerminalPrivateOpenTerminalProcessFunction:: 88 ~TerminalPrivateOpenTerminalProcessFunction() {} 89 90bool TerminalPrivateOpenTerminalProcessFunction::RunTerminalFunction() { 91 scoped_ptr<OpenTerminalProcess::Params> params( 92 OpenTerminalProcess::Params::Create(*args_)); 93 EXTENSION_FUNCTION_VALIDATE(params.get()); 94 95 command_ = GetProcessCommandForName(params->process_name); 96 if (!command_) { 97 error_ = "Invalid process name."; 98 return false; 99 } 100 101 // Registry lives on FILE thread. 102 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 103 base::Bind(&TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread, 104 this)); 105 return true; 106} 107 108void TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread() { 109 DCHECK(command_); 110 111 chromeos::ProcessProxyRegistry* registry = 112 chromeos::ProcessProxyRegistry::Get(); 113 pid_t pid; 114 if (!registry->OpenProcess( 115 command_, &pid, 116 base::Bind(&NotifyProcessOutput, profile_, extension_id()))) { 117 // If new process could not be opened, we return -1. 118 pid = -1; 119 } 120 121 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 122 base::Bind(&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread, 123 this, pid)); 124} 125 126TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {} 127 128void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) { 129 SetResult(new base::FundamentalValue(pid)); 130 SendResponse(true); 131} 132 133bool TerminalPrivateSendInputFunction::RunTerminalFunction() { 134 scoped_ptr<SendInput::Params> params(SendInput::Params::Create(*args_)); 135 EXTENSION_FUNCTION_VALIDATE(params.get()); 136 137 // Registry lives on the FILE thread. 138 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 139 base::Bind(&TerminalPrivateSendInputFunction::SendInputOnFileThread, 140 this, params->pid, params->input)); 141 return true; 142} 143 144void TerminalPrivateSendInputFunction::SendInputOnFileThread(pid_t pid, 145 const std::string& text) { 146 bool success = chromeos::ProcessProxyRegistry::Get()->SendInput(pid, text); 147 148 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 149 base::Bind(&TerminalPrivateSendInputFunction::RespondOnUIThread, this, 150 success)); 151} 152 153void TerminalPrivateSendInputFunction::RespondOnUIThread(bool success) { 154 SetResult(new base::FundamentalValue(success)); 155 SendResponse(true); 156} 157 158TerminalPrivateCloseTerminalProcessFunction:: 159 ~TerminalPrivateCloseTerminalProcessFunction() {} 160 161bool TerminalPrivateCloseTerminalProcessFunction::RunTerminalFunction() { 162 if (args_->GetSize() != 1) 163 return false; 164 pid_t pid; 165 if (!args_->GetInteger(0, &pid)) 166 return false; 167 168 // Registry lives on the FILE thread. 169 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 170 base::Bind(&TerminalPrivateCloseTerminalProcessFunction:: 171 CloseOnFileThread, this, pid)); 172 173 return true; 174} 175 176void TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread(pid_t pid) { 177 bool success = chromeos::ProcessProxyRegistry::Get()->CloseProcess(pid); 178 179 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 180 base::Bind(&TerminalPrivateCloseTerminalProcessFunction:: 181 RespondOnUIThread, this, success)); 182} 183 184void TerminalPrivateCloseTerminalProcessFunction::RespondOnUIThread( 185 bool success) { 186 SetResult(new base::FundamentalValue(success)); 187 SendResponse(true); 188} 189 190TerminalPrivateOnTerminalResizeFunction:: 191 ~TerminalPrivateOnTerminalResizeFunction() {} 192 193bool TerminalPrivateOnTerminalResizeFunction::RunTerminalFunction() { 194 scoped_ptr<OnTerminalResize::Params> params( 195 OnTerminalResize::Params::Create(*args_)); 196 EXTENSION_FUNCTION_VALIDATE(params.get()); 197 198 // Registry lives on the FILE thread. 199 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 200 base::Bind(&TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread, 201 this, params->pid, params->width, params->height)); 202 203 return true; 204} 205 206void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread(pid_t pid, 207 int width, int height) { 208 bool success = chromeos::ProcessProxyRegistry::Get()->OnTerminalResize( 209 pid, width, height); 210 211 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 212 base::Bind(&TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread, 213 this, success)); 214} 215 216void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) { 217 SetResult(new base::FundamentalValue(success)); 218 SendResponse(true); 219} 220