terminal_private_api.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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/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::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_, &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