Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2011 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/common/service_process_util.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/command_line.h"
      9 #include "base/files/file_path.h"
     10 #include "base/logging.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/path_service.h"
     13 #include "base/strings/string16.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/win/object_watcher.h"
     16 #include "base/win/scoped_handle.h"
     17 #include "base/win/win_util.h"
     18 #include "chrome/common/chrome_paths.h"
     19 #include "chrome/common/chrome_switches.h"
     20 
     21 namespace {
     22 
     23 const char* kTerminateEventSuffix = "_service_terminate_evt";
     24 
     25 base::string16 GetServiceProcessReadyEventName() {
     26   return UTF8ToWide(
     27       GetServiceProcessScopedVersionedName("_service_ready"));
     28 }
     29 
     30 base::string16 GetServiceProcessTerminateEventName() {
     31   return UTF8ToWide(
     32       GetServiceProcessScopedVersionedName(kTerminateEventSuffix));
     33 }
     34 
     35 std::string GetServiceProcessAutoRunKey() {
     36   return GetServiceProcessScopedName("_service_run");
     37 }
     38 
     39 // Returns the name of the autotun reg value that we used to use for older
     40 // versions of Chrome.
     41 std::string GetObsoleteServiceProcessAutoRunKey() {
     42   base::FilePath user_data_dir;
     43   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
     44   std::string scoped_name = WideToUTF8(user_data_dir.value());
     45   std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!');
     46   std::replace(scoped_name.begin(), scoped_name.end(), '/', '!');
     47   scoped_name.append("_service_run");
     48   return scoped_name;
     49 }
     50 
     51 class ServiceProcessTerminateMonitor
     52     : public base::win::ObjectWatcher::Delegate {
     53  public:
     54   explicit ServiceProcessTerminateMonitor(const base::Closure& terminate_task)
     55       : terminate_task_(terminate_task) {
     56   }
     57   void Start() {
     58     base::string16 event_name = GetServiceProcessTerminateEventName();
     59     DCHECK(event_name.length() <= MAX_PATH);
     60     terminate_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
     61     watcher_.StartWatching(terminate_event_.Get(), this);
     62   }
     63 
     64   // base::ObjectWatcher::Delegate implementation.
     65   virtual void OnObjectSignaled(HANDLE object) {
     66     if (!terminate_task_.is_null()) {
     67       terminate_task_.Run();
     68       terminate_task_.Reset();
     69     }
     70   }
     71 
     72  private:
     73   base::win::ScopedHandle terminate_event_;
     74   base::win::ObjectWatcher watcher_;
     75   base::Closure terminate_task_;
     76 };
     77 
     78 }  // namespace
     79 
     80 // Gets the name of the service process IPC channel.
     81 IPC::ChannelHandle GetServiceProcessChannel() {
     82   return GetServiceProcessScopedVersionedName("_service_ipc");
     83 }
     84 
     85 bool ForceServiceProcessShutdown(const std::string& version,
     86                                  base::ProcessId process_id) {
     87   base::win::ScopedHandle terminate_event;
     88   std::string versioned_name = version;
     89   versioned_name.append(kTerminateEventSuffix);
     90   base::string16 event_name =
     91       UTF8ToWide(GetServiceProcessScopedName(versioned_name));
     92   terminate_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str()));
     93   if (!terminate_event.IsValid())
     94     return false;
     95   SetEvent(terminate_event.Get());
     96   return true;
     97 }
     98 
     99 bool CheckServiceProcessReady() {
    100   base::string16 event_name = GetServiceProcessReadyEventName();
    101   base::win::ScopedHandle event(
    102       OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
    103   if (!event.IsValid())
    104     return false;
    105   // Check if the event is signaled.
    106   return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
    107 }
    108 
    109 struct ServiceProcessState::StateData {
    110   // An event that is signaled when a service process is ready.
    111   base::win::ScopedHandle ready_event;
    112   scoped_ptr<ServiceProcessTerminateMonitor> terminate_monitor;
    113 };
    114 
    115 void ServiceProcessState::CreateState() {
    116   DCHECK(!state_);
    117   state_ = new StateData;
    118 }
    119 
    120 bool ServiceProcessState::TakeSingletonLock() {
    121   DCHECK(state_);
    122   base::string16 event_name = GetServiceProcessReadyEventName();
    123   DCHECK(event_name.length() <= MAX_PATH);
    124   base::win::ScopedHandle service_process_ready_event;
    125   service_process_ready_event.Set(
    126       CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
    127   DWORD error = GetLastError();
    128   if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED))
    129     return false;
    130   DCHECK(service_process_ready_event.IsValid());
    131   state_->ready_event.Set(service_process_ready_event.Take());
    132   return true;
    133 }
    134 
    135 bool ServiceProcessState::SignalReady(
    136     base::MessageLoopProxy* message_loop_proxy,
    137     const base::Closure& terminate_task) {
    138   DCHECK(state_);
    139   DCHECK(state_->ready_event.IsValid());
    140   if (!SetEvent(state_->ready_event.Get())) {
    141     return false;
    142   }
    143   if (!terminate_task.is_null()) {
    144     state_->terminate_monitor.reset(
    145         new ServiceProcessTerminateMonitor(terminate_task));
    146     state_->terminate_monitor->Start();
    147   }
    148   return true;
    149 }
    150 
    151 bool ServiceProcessState::AddToAutoRun() {
    152   DCHECK(autorun_command_line_.get());
    153   // Remove the old autorun value first because we changed the naming scheme
    154   // for the autorun value name.
    155   base::win::RemoveCommandFromAutoRun(
    156       HKEY_CURRENT_USER, UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
    157   return base::win::AddCommandToAutoRun(
    158       HKEY_CURRENT_USER,
    159       UTF8ToWide(GetServiceProcessAutoRunKey()),
    160       autorun_command_line_->GetCommandLineString());
    161 }
    162 
    163 bool ServiceProcessState::RemoveFromAutoRun() {
    164   // Remove the old autorun value first because we changed the naming scheme
    165   // for the autorun value name.
    166   base::win::RemoveCommandFromAutoRun(
    167       HKEY_CURRENT_USER, UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
    168   return base::win::RemoveCommandFromAutoRun(
    169       HKEY_CURRENT_USER, UTF8ToWide(GetServiceProcessAutoRunKey()));
    170 }
    171 
    172 void ServiceProcessState::TearDownState() {
    173   delete state_;
    174   state_ = NULL;
    175 }
    176