summaryrefslogtreecommitdiffstats
path: root/chrome/common/service_process_util.cc
diff options
context:
space:
mode:
authorsanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-13 20:27:04 +0000
committersanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-13 20:27:04 +0000
commit146354945e1fb1a915ecb009c6732e0e28db9adc (patch)
tree248ec50922622796c7df09720b30c3f4ad6d2fa6 /chrome/common/service_process_util.cc
parent6da080717a2ef41e6292090427386d9079e73a59 (diff)
downloadchromium_src-146354945e1fb1a915ecb009c6732e0e28db9adc.zip
chromium_src-146354945e1fb1a915ecb009c6732e0e28db9adc.tar.gz
chromium_src-146354945e1fb1a915ecb009c6732e0e28db9adc.tar.bz2
Spilt code in service_process_utils.cc into separate files for Windows and Posix. Added unit-tests for this file. Also created a ServiceProcessState class that manages global state for the service process.
BUG=None TEST=Unit-tests, cloud print proxy. Review URL: http://codereview.chromium.org/3745001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62448 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/service_process_util.cc')
-rw-r--r--chrome/common/service_process_util.cc257
1 files changed, 61 insertions, 196 deletions
diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc
index 150ceb2..f636f2b 100644
--- a/chrome/common/service_process_util.cc
+++ b/chrome/common/service_process_util.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
-#include "base/shared_memory.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -16,13 +15,6 @@
#include "chrome/common/service_process_util.h"
#include "chrome/installer/util/version.h"
-#if defined(OS_WIN)
-#include "base/object_watcher.h"
-#include "base/scoped_handle_win.h"
-#endif
-
-// TODO(hclam): Split this file for different platforms.
-
namespace {
// This should be more than enough to hold a version string assuming each part
@@ -35,34 +27,6 @@ struct ServiceProcessSharedData {
base::ProcessId service_process_pid;
};
-// Return a name that is scoped to this instance of the service process. We
-// use the user-data-dir as a scoping prefix.
-std::string GetServiceProcessScopedName(const std::string& append_str) {
- FilePath user_data_dir;
- PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-#if defined(OS_WIN)
- std::string scoped_name = WideToUTF8(user_data_dir.value());
-#elif defined(OS_POSIX)
- std::string scoped_name = user_data_dir.value();
-#endif // defined(OS_WIN)
- std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!');
- std::replace(scoped_name.begin(), scoped_name.end(), '/', '!');
- scoped_name.append(append_str);
- return scoped_name;
-}
-
-// Return a name that is scoped to this instance of the service process. We
-// use the user-data-dir and the version as a scoping prefix.
-std::string GetServiceProcessScopedVersionedName(
- const std::string& append_str) {
- std::string versioned_str;
- chrome::VersionInfo version_info;
- DCHECK(version_info.is_valid());
- versioned_str.append(version_info.Version());
- versioned_str.append(append_str);
- return GetServiceProcessScopedName(versioned_str);
-}
-
// Gets the name of the shared memory used by the service process to write its
// version. The name is not versioned.
std::string GetServiceProcessSharedMemName() {
@@ -99,7 +63,6 @@ enum ServiceProcessRunningState {
SERVICE_NEWER_VERSION_RUNNING,
};
-#if defined(OS_WIN)
ServiceProcessRunningState GetServiceProcessRunningState(
std::string* service_version_out) {
std::string version;
@@ -143,85 +106,76 @@ ServiceProcessRunningState GetServiceProcessRunningState(
}
return SERVICE_SAME_VERSION_RUNNING;
}
-#endif // defined(OS_WIN)
-
-#if defined(OS_WIN)
-string16 GetServiceProcessReadyEventName() {
- return UTF8ToWide(
- GetServiceProcessScopedVersionedName("_service_ready"));
-}
-
-string16 GetServiceProcessShutdownEventName() {
- return UTF8ToWide(
- GetServiceProcessScopedVersionedName("_service_shutdown_evt"));
-}
-class ServiceProcessShutdownMonitor : public base::ObjectWatcher::Delegate {
- public:
- explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
- : shutdown_task_(shutdown_task) {
- }
- void Start() {
- string16 event_name = GetServiceProcessShutdownEventName();
- CHECK(event_name.length() <= MAX_PATH);
- shutdown_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
- watcher_.StartWatching(shutdown_event_.Get(), this);
- }
- // base::ObjectWatcher::Delegate implementation.
- virtual void OnObjectSignaled(HANDLE object) {
- shutdown_task_->Run();
- shutdown_task_.reset();
- }
+} // namespace
- private:
- ScopedHandle shutdown_event_;
- base::ObjectWatcher watcher_;
- scoped_ptr<Task> shutdown_task_;
-};
-#else // defined(OS_WIN)
-// Gets the name of the lock file for service process. Used on non-Windows OSes.
-FilePath GetServiceProcessLockFilePath() {
+// Return a name that is scoped to this instance of the service process. We
+// use the user-data-dir as a scoping prefix.
+std::string GetServiceProcessScopedName(const std::string& append_str) {
FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
- chrome::VersionInfo version_info;
- std::string lock_file_name = version_info.Version() + "Service Process Lock";
- return user_data_dir.Append(lock_file_name);
-}
-#endif // defined(OS_WIN)
-
-struct ServiceProcessGlobalState {
- scoped_ptr<base::SharedMemory> shared_mem_service_data;
#if defined(OS_WIN)
- // An event that is signaled when a service process is ready.
- ScopedHandle ready_event;
- scoped_ptr<ServiceProcessShutdownMonitor> shutdown_monitor;
+ std::string scoped_name = WideToUTF8(user_data_dir.value());
+#elif defined(OS_POSIX)
+ std::string scoped_name = user_data_dir.value();
#endif // defined(OS_WIN)
-};
-
-// TODO(sanjeevr): Remove this ugly global pointer and move all methods and
-// data members used by the service process into one singleton class which
-// could be owned by the service process.
-ServiceProcessGlobalState* g_service_globals = NULL;
+ std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!');
+ std::replace(scoped_name.begin(), scoped_name.end(), '/', '!');
+ scoped_name.append(append_str);
+ return scoped_name;
+}
-} // namespace
+// Return a name that is scoped to this instance of the service process. We
+// use the user-data-dir and the version as a scoping prefix.
+std::string GetServiceProcessScopedVersionedName(
+ const std::string& append_str) {
+ std::string versioned_str;
+ chrome::VersionInfo version_info;
+ DCHECK(version_info.is_valid());
+ versioned_str.append(version_info.Version());
+ versioned_str.append(append_str);
+ return GetServiceProcessScopedName(versioned_str);
+}
// Gets the name of the service process IPC channel.
std::string GetServiceProcessChannelName() {
return GetServiceProcessScopedVersionedName("_service_ipc");
}
-std::string GetServiceProcessAutoRunKey() {
- return GetServiceProcessScopedName("_service_run");
+base::ProcessId GetServiceProcessPid() {
+ base::ProcessId pid = 0;
+ GetServiceProcessSharedData(NULL, &pid);
+ return pid;
}
-bool TakeServiceProcessSingletonLock() {
- DCHECK(g_service_globals == NULL);
- // On Linux shared menory is implemented using file. In case of incorrect
- // shutdown or process kill memshared file stay on the disk and prevents
- // next instance of service from starting. So, on Linux we have to disable
- // check for another running instance of the service.
-#if defined(OS_WIN)
+ServiceProcessState::ServiceProcessState() : state_(NULL) {
+}
+
+ServiceProcessState::~ServiceProcessState() {
+ TearDownState();
+}
+
+bool ServiceProcessState::Initialize() {
+ if (!TakeSingletonLock()) {
+ return false;
+ }
+ // Now that we have the singleton, take care of killing an older version, if
+ // it exists.
+ if (ShouldHandleOtherVersion() && !HandleOtherVersion())
+ return false;
+
+ // TODO(sanjeevr): We can probably use the shared mem as the sole singleton
+ // mechanism. For that the shared mem class needs to return whether it created
+ // new instance or opened an existing one. Also shared memory on Linux uses
+ // a file on disk which is not deleted when the process exits.
+
+ // Now that we have the singleton, let is also write the version we are using
+ // to shared memory. This can be used by a newer service to signal us to exit.
+ return CreateSharedData();
+}
+
+bool ServiceProcessState::HandleOtherVersion() {
std::string running_version;
ServiceProcessRunningState state =
GetServiceProcessRunningState(&running_version);
@@ -236,31 +190,10 @@ bool TakeServiceProcessSingletonLock() {
case SERVICE_NOT_RUNNING:
break;
}
-#endif
- g_service_globals = new ServiceProcessGlobalState;
- // TODO(sanjeevr): We can probably use the shared mem as the sole singleton
- // mechanism. For that the shared mem class needs to return whether it created
- // new instance or opened an existing one.
-#if defined(OS_WIN)
- string16 event_name = GetServiceProcessReadyEventName();
- CHECK(event_name.length() <= MAX_PATH);
- ScopedHandle service_process_ready_event;
- service_process_ready_event.Set(
- CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
- DWORD error = GetLastError();
- if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED)) {
- delete g_service_globals;
- g_service_globals = NULL;
- return false;
- }
- DCHECK(service_process_ready_event.IsValid());
- g_service_globals->ready_event.Set(service_process_ready_event.Take());
-#else
- // TODO(sanjeevr): Implement singleton mechanism for other platforms.
- NOTIMPLEMENTED();
-#endif
- // Now that we have the singleton, let is also write the version we are using
- // to shared memory. This can be used by a newer service to signal us to exit.
+ return true;
+}
+
+bool ServiceProcessState::CreateSharedData() {
chrome::VersionInfo version_info;
if (!version_info.is_valid()) {
NOTREACHED() << "Failed to get current file version";
@@ -293,80 +226,12 @@ bool TakeServiceProcessSingletonLock() {
memcpy(shared_data->service_process_version, version_info.Version().c_str(),
version_info.Version().length());
shared_data->service_process_pid = base::GetCurrentProcId();
- g_service_globals->shared_mem_service_data.reset(
- shared_mem_service_data.release());
- return true;
-}
-
-void SignalServiceProcessReady(Task* shutdown_task) {
-#if defined(OS_WIN)
- DCHECK(g_service_globals != NULL);
- DCHECK(g_service_globals->ready_event.IsValid());
- SetEvent(g_service_globals->ready_event.Get());
- g_service_globals->shutdown_monitor.reset(
- new ServiceProcessShutdownMonitor(shutdown_task));
- g_service_globals->shutdown_monitor->Start();
-#else
- // TODO(hclam): Implement better mechanism for these platform.
- // Also we need to save shutdown task. For now we just delete the shutdown
- // task because we have not way to listen for shutdown requests.
- delete shutdown_task;
- const FilePath path = GetServiceProcessLockFilePath();
- FILE* file = file_util::OpenFile(path, "wb+");
- if (!file)
- return;
- LOG(INFO) << "Created Service Process lock file: " << path.value();
- file_util::TruncateFile(file) && file_util::CloseFile(file);
-#endif
-}
-
-void SignalServiceProcessStopped() {
- delete g_service_globals;
- g_service_globals = NULL;
-#if !defined(OS_WIN)
- // TODO(hclam): Implement better mechanism for these platform.
- const FilePath path = GetServiceProcessLockFilePath();
- file_util::Delete(path, false);
-#endif
-}
-
-bool ForceServiceProcessShutdown(const std::string& version) {
-#if defined(OS_WIN)
- ScopedHandle shutdown_event;
- std::string versioned_name = version;
- versioned_name.append("_service_shutdown_evt");
- string16 event_name =
- UTF8ToWide(GetServiceProcessScopedName(versioned_name));
- shutdown_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str()));
- if (!shutdown_event.IsValid())
- return false;
- SetEvent(shutdown_event.Get());
+ shared_mem_service_data_.reset(shared_mem_service_data.release());
return true;
-#else // defined(OS_WIN)
- NOTIMPLEMENTED();
- return false;
-#endif // defined(OS_WIN)
}
-bool CheckServiceProcessReady() {
-#if defined(OS_WIN)
- string16 event_name = GetServiceProcessReadyEventName();
- ScopedHandle event(
- OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
- if (!event.IsValid())
- return false;
- // Check if the event is signaled.
- return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
-#else
- // TODO(hclam): Implement better mechanism for these platform.
- const FilePath path = GetServiceProcessLockFilePath();
- return file_util::PathExists(path);
-#endif
-}
-base::ProcessId GetServiceProcessPid() {
- base::ProcessId pid = 0;
- GetServiceProcessSharedData(NULL, &pid);
- return pid;
+std::string ServiceProcessState::GetAutoRunKey() {
+ return GetServiceProcessScopedName("_service_run");
}