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