Home | History | Annotate | Download | only in terminal
      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 
     33 const char* GetCroshPath() {
     34   if (base::SysInfo::IsRunningOnChromeOS())
     35     return kCroshCommand;
     36   else
     37     return kStubbedCroshCommand;
     38 }
     39 
     40 const char* GetProcessCommandForName(const std::string& name) {
     41   if (name == kCroshName)
     42     return GetCroshPath();
     43   else
     44     return NULL;
     45 }
     46 
     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 
     76 TerminalPrivateFunction::TerminalPrivateFunction() {}
     77 
     78 TerminalPrivateFunction::~TerminalPrivateFunction() {}
     79 
     80 bool TerminalPrivateFunction::RunAsync() {
     81   return RunTerminalFunction();
     82 }
     83 
     84 TerminalPrivateOpenTerminalProcessFunction::
     85     TerminalPrivateOpenTerminalProcessFunction() : command_(NULL) {}
     86 
     87 TerminalPrivateOpenTerminalProcessFunction::
     88     ~TerminalPrivateOpenTerminalProcessFunction() {}
     89 
     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 
    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 
    127 TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {}
    128 
    129 void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) {
    130   SetResult(new base::FundamentalValue(pid));
    131   SendResponse(true);
    132 }
    133 
    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 
    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 
    154 void TerminalPrivateSendInputFunction::RespondOnUIThread(bool success) {
    155   SetResult(new base::FundamentalValue(success));
    156   SendResponse(true);
    157 }
    158 
    159 TerminalPrivateCloseTerminalProcessFunction::
    160     ~TerminalPrivateCloseTerminalProcessFunction() {}
    161 
    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 
    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 
    185 void TerminalPrivateCloseTerminalProcessFunction::RespondOnUIThread(
    186     bool success) {
    187   SetResult(new base::FundamentalValue(success));
    188   SendResponse(true);
    189 }
    190 
    191 TerminalPrivateOnTerminalResizeFunction::
    192     ~TerminalPrivateOnTerminalResizeFunction() {}
    193 
    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 
    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 
    217 void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) {
    218   SetResult(new base::FundamentalValue(success));
    219   SendResponse(true);
    220 }
    221 
    222 }  // namespace extensions
    223