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/chromeos/chromeos_version.h"
      9 #include "base/json/json_writer.h"
     10 #include "base/values.h"
     11 #include "chrome/browser/extensions/api/terminal/terminal_extension_helper.h"
     12 #include "chrome/browser/extensions/event_names.h"
     13 #include "chrome/browser/extensions/event_router.h"
     14 #include "chrome/browser/extensions/extension_service.h"
     15 #include "chrome/browser/extensions/extension_system.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/common/extensions/api/terminal_private.h"
     18 #include "chromeos/process_proxy/process_proxy_registry.h"
     19 #include "content/public/browser/browser_thread.h"
     20 
     21 namespace OnTerminalResize =
     22     extensions::api::terminal_private::OnTerminalResize;
     23 namespace OpenTerminalProcess =
     24     extensions::api::terminal_private::OpenTerminalProcess;
     25 namespace SendInput = extensions::api::terminal_private::SendInput;
     26 
     27 namespace {
     28 
     29 const char kCroshName[] = "crosh";
     30 const char kCroshCommand[] = "/usr/bin/crosh";
     31 // We make stubbed crosh just echo back input.
     32 const char kStubbedCroshCommand[] = "cat";
     33 
     34 const char* GetCroshPath() {
     35   if (base::chromeos::IsRunningOnChromeOS())
     36     return kCroshCommand;
     37   else
     38     return kStubbedCroshCommand;
     39 }
     40 
     41 const char* GetProcessCommandForName(const std::string& name) {
     42   if (name == kCroshName)
     43     return GetCroshPath();
     44   else
     45     return NULL;
     46 }
     47 
     48 void 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         extensions::event_names::kOnTerminalProcessOutput, args.Pass()));
     69     extensions::ExtensionSystem::Get(profile)->event_router()->
     70         DispatchEventToExtension(extension_id, event.Pass());
     71   }
     72 }
     73 
     74 }  // namespace
     75 
     76 TerminalPrivateFunction::TerminalPrivateFunction() {}
     77 
     78 TerminalPrivateFunction::~TerminalPrivateFunction() {}
     79 
     80 bool TerminalPrivateFunction::RunImpl() {
     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_, &pid,
    116           base::Bind(&NotifyProcessOutput, profile_, extension_id()))) {
    117     // If new process could not be opened, we return -1.
    118     pid = -1;
    119   }
    120 
    121   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    122       base::Bind(&TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread,
    123                  this, pid));
    124 }
    125 
    126 TerminalPrivateSendInputFunction::~TerminalPrivateSendInputFunction() {}
    127 
    128 void TerminalPrivateOpenTerminalProcessFunction::RespondOnUIThread(pid_t pid) {
    129   SetResult(new base::FundamentalValue(pid));
    130   SendResponse(true);
    131 }
    132 
    133 bool TerminalPrivateSendInputFunction::RunTerminalFunction() {
    134   scoped_ptr<SendInput::Params> params(SendInput::Params::Create(*args_));
    135   EXTENSION_FUNCTION_VALIDATE(params.get());
    136 
    137   // Registry lives on the FILE thread.
    138   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
    139       base::Bind(&TerminalPrivateSendInputFunction::SendInputOnFileThread,
    140                  this, params->pid, params->input));
    141   return true;
    142 }
    143 
    144 void TerminalPrivateSendInputFunction::SendInputOnFileThread(pid_t pid,
    145     const std::string& text) {
    146   bool success = chromeos::ProcessProxyRegistry::Get()->SendInput(pid, text);
    147 
    148   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    149       base::Bind(&TerminalPrivateSendInputFunction::RespondOnUIThread, this,
    150       success));
    151 }
    152 
    153 void TerminalPrivateSendInputFunction::RespondOnUIThread(bool success) {
    154   SetResult(new base::FundamentalValue(success));
    155   SendResponse(true);
    156 }
    157 
    158 TerminalPrivateCloseTerminalProcessFunction::
    159     ~TerminalPrivateCloseTerminalProcessFunction() {}
    160 
    161 bool TerminalPrivateCloseTerminalProcessFunction::RunTerminalFunction() {
    162   if (args_->GetSize() != 1)
    163     return false;
    164   pid_t pid;
    165   if (!args_->GetInteger(0, &pid))
    166     return false;
    167 
    168   // Registry lives on the FILE thread.
    169   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
    170       base::Bind(&TerminalPrivateCloseTerminalProcessFunction::
    171                  CloseOnFileThread, this, pid));
    172 
    173   return true;
    174 }
    175 
    176 void TerminalPrivateCloseTerminalProcessFunction::CloseOnFileThread(pid_t pid) {
    177   bool success = chromeos::ProcessProxyRegistry::Get()->CloseProcess(pid);
    178 
    179   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    180       base::Bind(&TerminalPrivateCloseTerminalProcessFunction::
    181                  RespondOnUIThread, this, success));
    182 }
    183 
    184 void TerminalPrivateCloseTerminalProcessFunction::RespondOnUIThread(
    185     bool success) {
    186   SetResult(new base::FundamentalValue(success));
    187   SendResponse(true);
    188 }
    189 
    190 TerminalPrivateOnTerminalResizeFunction::
    191     ~TerminalPrivateOnTerminalResizeFunction() {}
    192 
    193 bool TerminalPrivateOnTerminalResizeFunction::RunTerminalFunction() {
    194   scoped_ptr<OnTerminalResize::Params> params(
    195       OnTerminalResize::Params::Create(*args_));
    196   EXTENSION_FUNCTION_VALIDATE(params.get());
    197 
    198   // Registry lives on the FILE thread.
    199   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
    200       base::Bind(&TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread,
    201                  this, params->pid, params->width, params->height));
    202 
    203   return true;
    204 }
    205 
    206 void TerminalPrivateOnTerminalResizeFunction::OnResizeOnFileThread(pid_t pid,
    207                                                     int width, int height) {
    208   bool success = chromeos::ProcessProxyRegistry::Get()->OnTerminalResize(
    209       pid, width, height);
    210 
    211   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
    212       base::Bind(&TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread,
    213                  this, success));
    214 }
    215 
    216 void TerminalPrivateOnTerminalResizeFunction::RespondOnUIThread(bool success) {
    217   SetResult(new base::FundamentalValue(success));
    218   SendResponse(true);
    219 }
    220