terminal_private_api.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 "chromeos/process_proxy/process_proxy_registry.h" 12#include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h" 13#include "chrome/browser/extensions/event_names.h" 14#include "chrome/browser/extensions/event_router.h" 15#include "chrome/browser/extensions/extension_service.h" 16#include "chrome/browser/extensions/extension_system.h" 17#include "chrome/browser/profiles/profile.h" 18#include "content/public/browser/browser_thread.h" 19 20namespace { 21 22const char kCroshName[] = "crosh"; 23const char kCroshCommand[] = "/usr/bin/crosh"; 24// We make stubbed crosh just echo back input. 25const char kStubbedCroshCommand[] = "cat"; 26 27const char* GetCroshPath() { 28 if (base::chromeos::IsRunningOnChromeOS()) 29 return kCroshCommand; 30 else 31 return kStubbedCroshCommand; 32} 33 34const char* GetProcessCommandForName(const std::string& name) { 35 if (name == kCroshName) { 36 return GetCroshPath(); 37 } else { 38 return NULL; 39 } 40} 41 42void NotifyProcessOutput(Profile* profile, 43 const std::string& extension_id, 44 pid_t pid, 45 const std::string& output_type, 46 const std::string& output) { 47 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { 48 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 49 base::Bind(&NotifyProcessOutput, profile, extension_id, 50 pid, output_type, output)); 51 return; 52 } 53 54 scoped_ptr<base::ListValue> args(new base::ListValue()); 55 args->Append(new base::FundamentalValue(pid)); 56 args->Append(new base::StringValue(output_type)); 57 args->Append(new base::StringValue(output)); 58 59 if (profile && 60 extensions::ExtensionSystem::Get(profile)->event_router()) { 61 scoped_ptr<extensions::Event> event(new extensions::Event( 62 extensions::event_names::kOnTerminalProcessOutput, args.Pass())); 63 extensions::ExtensionSystem::Get(profile)->event_router()-> 64 DispatchEventToExtension(extension_id, event.Pass()); 65 } 66} 67 68} // namespace 69 70TerminalPrivateFunction::TerminalPrivateFunction() {} 71 72TerminalPrivateFunction::~TerminalPrivateFunction() {} 73 74bool TerminalPrivateFunction::RunImpl() { 75 return RunTerminalFunction(); 76} 77 78TerminalPrivateOpenTerminalProcessFunction:: 79 TerminalPrivateOpenTerminalProcessFunction() : command_(NULL) {} 80 81TerminalPrivateOpenTerminalProcessFunction:: 82 ~TerminalPrivateOpenTerminalProcessFunction() {} 83 84bool TerminalPrivateOpenTerminalProcessFunction::RunTerminalFunction() { 85 if (args_->GetSize() != 1) 86 return false; 87 88 std::string name; 89 if (!args_->GetString(0, &name)) 90 return false; 91 92 command_ = GetProcessCommandForName(name); 93 if (!command_) { 94 error_ = "Invalid process name."; 95 return false; 96 } 97 98 // Registry lives on FILE thread. 99 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 100 base::Bind(&TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread, 101 this)); 102 return true; 103} 104 105void TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread() { 106 DCHECK(command_); 107 108 chromeos::ProcessProxyRegistry* registry = 109 chromeos::ProcessProxyRegistry::Get(); 110 pid_t pid; 111 if (!registry->OpenProcess( 112 command_, &pid, 113 base::Bind(&NotifyProcessOutput, profile_, extension_id()))) { 114 // If new process could not be opened, we return -1. 115 pid = -1; 116 } 117 118 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 119 base::Bind(&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread, 120 this, pid)); 121} 122 123TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {} 124 125void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) { 126 SetResult(new base::FundamentalValue(pid)); 127 SendResponse(true); 128} 129 130bool TerminalPrivateSendInputFunction::RunTerminalFunction() { 131 if (args_->GetSize() != 2) 132 return false; 133 134 pid_t pid; 135 std::string text; 136 if (!args_->GetInteger(0, &pid) || !args_->GetString(1, &text)) 137 return false; 138 139 // Registry lives on the FILE thread. 140 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 141 base::Bind(&TerminalPrivateSendInputFunction::SendInputOnFileThread, 142 this, pid, text)); 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 if (args_->GetSize() != 3) 197 return false; 198 199 pid_t pid; 200 if (!args_->GetInteger(0, &pid)) 201 return false; 202 203 int width; 204 if (!args_->GetInteger(1, &width)) 205 return false; 206 207 int height; 208 if (!args_->GetInteger(2, &height)) 209 return false; 210 211 // Registry lives on the FILE thread. 212 content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE, 213 base::Bind(&TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread, 214 this, pid, width, height)); 215 216 return true; 217} 218 219void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread(pid_t pid, 220 int width, int height) { 221 bool success = chromeos::ProcessProxyRegistry::Get()->OnTerminalResize( 222 pid, width, height); 223 224 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 225 base::Bind(&TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread, 226 this, success)); 227} 228 229void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) { 230 SetResult(new base::FundamentalValue(success)); 231 SendResponse(true); 232} 233