terminal_private_api.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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#include "extensions/browser/extension_system.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