18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Copyright (c) 2011 The Chromium Authors. All rights reserved.
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Use of this source code is governed by a BSD-style license that can be
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// found in the LICENSE file.
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "chrome/common/service_process_util.h"
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/command_line.h"
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/file_util.h"
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/logging.h"
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/memory/scoped_ptr.h"
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/path_service.h"
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/string16.h"
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/task.h"
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/utf_string_conversions.h"
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/win/object_watcher.h"
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/win/scoped_handle.h"
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "base/win/win_util.h"
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "chrome/common/chrome_paths.h"
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "chrome/common/chrome_switches.h"
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace {
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstring16 GetServiceProcessReadyEventName() {
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return UTF8ToWide(
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      GetServiceProcessScopedVersionedName("_service_ready"));
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstring16 GetServiceProcessShutdownEventName() {
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return UTF8ToWide(
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      GetServiceProcessScopedVersionedName("_service_shutdown_evt"));
31643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstd::string GetServiceProcessAutoRunKey() {
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return GetServiceProcessScopedName("_service_run");
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Returns the name of the autotun reg value that we used to use for older
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// versions of Chrome.
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstd::string GetObsoleteServiceProcessAutoRunKey() {
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  FilePath user_data_dir;
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  std::string scoped_name = WideToUTF8(user_data_dir.value());
43635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project  std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!');
44231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block  std::replace(scoped_name.begin(), scoped_name.end(), '/', '!');
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  scoped_name.append("_service_run");
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return scoped_name;
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
48231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectclass ServiceProcessShutdownMonitor
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : public base::win::ObjectWatcher::Delegate {
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project public:
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      : shutdown_task_(shutdown_task) {
54635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project  }
55231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block  void Start() {
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    string16 event_name = GetServiceProcessShutdownEventName();
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CHECK(event_name.length() <= MAX_PATH);
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    shutdown_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
59231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    watcher_.StartWatching(shutdown_event_.Get(), this);
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  }
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  // base::ObjectWatcher::Delegate implementation.
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  virtual void OnObjectSignaled(HANDLE object) {
64635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    shutdown_task_->Run();
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    shutdown_task_.reset();
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  }
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
68231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block private:
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  base::win::ScopedHandle shutdown_event_;
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  base::win::ObjectWatcher watcher_;
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  scoped_ptr<Task> shutdown_task_;
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}  // namespace
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool ForceServiceProcessShutdown(const std::string& version,
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                 base::ProcessId process_id) {
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  base::win::ScopedHandle shutdown_event;
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  std::string versioned_name = version;
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  versioned_name.append("_service_shutdown_evt");
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  string16 event_name =
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      UTF8ToWide(GetServiceProcessScopedName(versioned_name));
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  shutdown_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str()));
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  if (!shutdown_event.IsValid())
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  SetEvent(shutdown_event.Get());
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return true;
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool CheckServiceProcessReady() {
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  string16 event_name = GetServiceProcessReadyEventName();
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  base::win::ScopedHandle event(
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  if (!event.IsValid())
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  // Check if the event is signaled.
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstruct ServiceProcessState::StateData {
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  // An event that is signaled when a service process is ready.
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  base::win::ScopedHandle ready_event;
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  scoped_ptr<ServiceProcessShutdownMonitor> shutdown_monitor;
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid ServiceProcessState::CreateState() {
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  CHECK(!state_);
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  state_ = new StateData;
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool ServiceProcessState::TakeSingletonLock() {
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  DCHECK(state_);
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  string16 event_name = GetServiceProcessReadyEventName();
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  CHECK(event_name.length() <= MAX_PATH);
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  base::win::ScopedHandle service_process_ready_event;
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  service_process_ready_event.Set(
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  DWORD error = GetLastError();
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED))
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  DCHECK(service_process_ready_event.IsValid());
122643ca7872b450ea4efacab6188849e5aac2ba161Steve Block  state_->ready_event.Set(service_process_ready_event.Take());
123643ca7872b450ea4efacab6188849e5aac2ba161Steve Block  return true;
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool ServiceProcessState::SignalReady(
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) {
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  DCHECK(state_);
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  DCHECK(state_->ready_event.IsValid());
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  scoped_ptr<Task> scoped_shutdown_task(shutdown_task);
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  if (!SetEvent(state_->ready_event.Get())) {
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  }
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  if (shutdown_task) {
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    state_->shutdown_monitor.reset(
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        new ServiceProcessShutdownMonitor(scoped_shutdown_task.release()));
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    state_->shutdown_monitor->Start();
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  }
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return true;
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
141643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool ServiceProcessState::AddToAutoRun() {
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  DCHECK(autorun_command_line_.get());
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  // Remove the old autorun value first because we changed the naming scheme
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  // for the autorun value name.
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  base::win::RemoveCommandFromAutoRun(
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      HKEY_CURRENT_USER, UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return base::win::AddCommandToAutoRun(
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      HKEY_CURRENT_USER,
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      UTF8ToWide(GetServiceProcessAutoRunKey()),
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      autorun_command_line_->command_line_string());
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
154643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockbool ServiceProcessState::RemoveFromAutoRun() {
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  // Remove the old autorun value first because we changed the naming scheme
156643ca7872b450ea4efacab6188849e5aac2ba161Steve Block  // for the autorun value name.
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  base::win::RemoveCommandFromAutoRun(
158643ca7872b450ea4efacab6188849e5aac2ba161Steve Block      HKEY_CURRENT_USER, UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  return base::win::RemoveCommandFromAutoRun(
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project      HKEY_CURRENT_USER, UTF8ToWide(GetServiceProcessAutoRunKey()));
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid ServiceProcessState::TearDownState() {
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  delete state_;
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project  state_ = NULL;
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project