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