diff options
author | sanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-13 20:27:04 +0000 |
---|---|---|
committer | sanjeevr@chromium.org <sanjeevr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-13 20:27:04 +0000 |
commit | 146354945e1fb1a915ecb009c6732e0e28db9adc (patch) | |
tree | 248ec50922622796c7df09720b30c3f4ad6d2fa6 /chrome/common/service_process_util.cc | |
parent | 6da080717a2ef41e6292090427386d9079e73a59 (diff) | |
download | chromium_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.cc | 257 |
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"); } |