• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/profiles/profile.h"
14 #include "chrome/common/extensions/api/terminal_private.h"
15 #include "chromeos/process_proxy/process_proxy_registry.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "extensions/browser/event_router.h"
18 
19 namespace terminal_private = extensions::api::terminal_private;
20 namespace OnTerminalResize =
21     extensions::api::terminal_private::OnTerminalResize;
22 namespace OpenTerminalProcess =
23     extensions::api::terminal_private::OpenTerminalProcess;
24 namespace SendInput = extensions::api::terminal_private::SendInput;
25 
26 namespace {
27 
28 const char kCroshName[] = "crosh";
29 const char kCroshCommand[] = "/usr/bin/crosh";
30 // We make stubbed crosh just echo back input.
31 const char kStubbedCroshCommand[] = "cat";
32 
GetCroshPath()33 const char* GetCroshPath() {
34   if (base::SysInfo::IsRunningOnChromeOS())
35     return kCroshCommand;
36   else
37     return kStubbedCroshCommand;
38 }
39 
GetProcessCommandForName(const std::string & name)40 const char* GetProcessCommandForName(const std::string& name) {
41   if (name == kCroshName)
42     return GetCroshPath();
43   else
44     return NULL;
45 }
46 
NotifyProcessOutput(Profile * profile,const std::string & extension_id,pid_t pid,const std::string & output_type,const std::string & output)47 void NotifyProcessOutput(Profile* profile,
48                          const std::string& extension_id,
49                          pid_t pid,
50                          const std::string& output_type,
51                          const std::string& output) {
52   if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
53     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
54         base::Bind(&NotifyProcessOutput, profile, extension_id,
55                                          pid, output_type, output));
56     return;
57   }
58 
59   scoped_ptr<base::ListValue> args(new base::ListValue());
60   args->Append(new base::FundamentalValue(pid));
61   args->Append(new base::StringValue(output_type));
62   args->Append(new base::StringValue(output));
63 
64   extensions::EventRouter* event_router = extensions::EventRouter::Get(profile);
65   if (profile && event_router) {
66     scoped_ptr<extensions::Event> event(new extensions::Event(
67         terminal_private::OnProcessOutput::kEventName, args.Pass()));
68         event_router->DispatchEventToExtension(extension_id, event.Pass());
69   }
70 }
71 
72 }  // namespace
73 
74 namespace extensions {
75 
TerminalPrivateFunction()76 TerminalPrivateFunction::TerminalPrivateFunction() {}
77 
~TerminalPrivateFunction()78 TerminalPrivateFunction::~TerminalPrivateFunction() {}
79 
RunAsync()80 bool TerminalPrivateFunction::RunAsync() {
81   return RunTerminalFunction();
82 }
83 
84 TerminalPrivateOpenTerminalProcessFunction::
TerminalPrivateOpenTerminalProcessFunction()85     TerminalPrivateOpenTerminalProcessFunction() : command_(NULL) {}
86 
87 TerminalPrivateOpenTerminalProcessFunction::
~TerminalPrivateOpenTerminalProcessFunction()88     ~TerminalPrivateOpenTerminalProcessFunction() {}
89 
RunTerminalFunction()90 bool 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 
OpenOnFileThread()108 void TerminalPrivateOpenTerminalProcessFunction::OpenOnFileThread() {
109   DCHECK(command_);
110 
111   chromeos::ProcessProxyRegistry* registry =
112       chromeos::ProcessProxyRegistry::Get();
113   pid_t pid;
114   if (!registry->OpenProcess(
115            command_,
116            &pid,
117            base::Bind(&NotifyProcessOutput, GetProfile(), extension_id()))) {
118     // If new process could not be opened, we return -1.
119     pid = -1;
120   }
121 
122   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
123       base::Bind(&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread,
124                  this, pid));
125 }
126 
~TerminalPrivateSendInputFunction()127 TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {}
128 
RespondOnUIThread(pid_t pid)129 void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) {
130   SetResult(new base::FundamentalValue(pid));
131   SendResponse(true);
132 }
133 
RunTerminalFunction()134 bool TerminalPrivateSendInputFunction::RunTerminalFunction() {
135   scoped_ptr<SendInput::Params> params(SendInput::Params::Create(*args_));
136   EXTENSION_FUNCTION_VALIDATE(params.get());
137 
138   // Registry lives on the FILE thread.
139   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
140       base::Bind(&TerminalPrivateSendInputFunction::SendInputOnFileThread,
141                  this, params->pid, params->input));
142   return true;
143 }
144 
SendInputOnFileThread(pid_t pid,const std::string & text)145 void TerminalPrivateSendInputFunction::SendInputOnFileThread(pid_t pid,
146     const std::string& text) {
147   bool success = chromeos::ProcessProxyRegistry::Get()->SendInput(pid, text);
148 
149   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
150       base::Bind(&TerminalPrivateSendInputFunction::RespondOnUIThread, this,
151       success));
152 }
153 
RespondOnUIThread(bool success)154 void TerminalPrivateSendInputFunction::RespondOnUIThread(bool success) {
155   SetResult(new base::FundamentalValue(success));
156   SendResponse(true);
157 }
158 
159 TerminalPrivateCloseTerminalProcessFunction::
~TerminalPrivateCloseTerminalProcessFunction()160     ~TerminalPrivateCloseTerminalProcessFunction() {}
161 
RunTerminalFunction()162 bool TerminalPrivateCloseTerminalProcessFunction::RunTerminalFunction() {
163   if (args_->GetSize() != 1)
164     return false;
165   pid_t pid;
166   if (!args_->GetInteger(0, &pid))
167     return false;
168 
169   // Registry lives on the FILE thread.
170   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
171       base::Bind(&TerminalPrivateCloseTerminalProcessFunction::
172                  CloseOnFileThread, this, pid));
173 
174   return true;
175 }
176 
CloseOnFileThread(pid_t pid)177 void TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread(pid_t pid) {
178   bool success = chromeos::ProcessProxyRegistry::Get()->CloseProcess(pid);
179 
180   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
181       base::Bind(&TerminalPrivateCloseTerminalProcessFunction::
182                  RespondOnUIThread, this, success));
183 }
184 
RespondOnUIThread(bool success)185 void TerminalPrivateCloseTerminalProcessFunction::RespondOnUIThread(
186     bool success) {
187   SetResult(new base::FundamentalValue(success));
188   SendResponse(true);
189 }
190 
191 TerminalPrivateOnTerminalResizeFunction::
~TerminalPrivateOnTerminalResizeFunction()192     ~TerminalPrivateOnTerminalResizeFunction() {}
193 
RunTerminalFunction()194 bool TerminalPrivateOnTerminalResizeFunction::RunTerminalFunction() {
195   scoped_ptr<OnTerminalResize::Params> params(
196       OnTerminalResize::Params::Create(*args_));
197   EXTENSION_FUNCTION_VALIDATE(params.get());
198 
199   // Registry lives on the FILE thread.
200   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
201       base::Bind(&TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread,
202                  this, params->pid, params->width, params->height));
203 
204   return true;
205 }
206 
OnResizeOnFileThread(pid_t pid,int width,int height)207 void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread(pid_t pid,
208                                                     int width, int height) {
209   bool success = chromeos::ProcessProxyRegistry::Get()->OnTerminalResize(
210       pid, width, height);
211 
212   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
213       base::Bind(&TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread,
214                  this, success));
215 }
216 
RespondOnUIThread(bool success)217 void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) {
218   SetResult(new base::FundamentalValue(success));
219   SendResponse(true);
220 }
221 
222 }  // namespace extensions
223