Index: chrome/common/service_process_util.cc |
diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc |
index 4062e0f21d877ee2f63ee7d2b8be864666e9d067..458f66210349bd747347248e9f68dd7cce873ea4 100644 |
--- a/chrome/common/service_process_util.cc |
+++ b/chrome/common/service_process_util.cc |
@@ -6,10 +6,13 @@ |
#include "base/file_util.h" |
#include "base/logging.h" |
+#include "base/mac/scoped_nsautorelease_pool.h" |
#include "base/path_service.h" |
#include "base/process_util.h" |
+#include "base/sha1.h" |
#include "base/singleton.h" |
#include "base/string16.h" |
+#include "base/string_number_conversions.h" |
#include "base/string_util.h" |
#include "base/utf_string_conversions.h" |
#include "base/version.h" |
@@ -36,29 +39,6 @@ std::string GetServiceProcessSharedMemName() { |
return GetServiceProcessScopedName("_service_shmem"); |
} |
-// Reads the named shared memory to get the shared data. Returns false if no |
-// matching shared memory was found. |
-bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid) { |
- scoped_ptr<base::SharedMemory> shared_mem_service_data; |
- shared_mem_service_data.reset(new base::SharedMemory()); |
- ServiceProcessSharedData* service_data = NULL; |
- if (shared_mem_service_data.get() && |
- shared_mem_service_data->Open(GetServiceProcessSharedMemName(), true) && |
- shared_mem_service_data->Map(sizeof(ServiceProcessSharedData))) { |
- service_data = reinterpret_cast<ServiceProcessSharedData*>( |
- shared_mem_service_data->memory()); |
- // Make sure the version in shared memory is null-terminated. If it is not, |
- // treat it as invalid. |
- if (version && memchr(service_data->service_process_version, '\0', |
- sizeof(service_data->service_process_version))) |
- *version = service_data->service_process_version; |
- if (pid) |
- *pid = service_data->service_process_pid; |
- return true; |
- } |
- return false; |
-} |
- |
enum ServiceProcessRunningState { |
SERVICE_NOT_RUNNING, |
SERVICE_OLDER_VERSION_RUNNING, |
@@ -67,12 +47,20 @@ enum ServiceProcessRunningState { |
}; |
ServiceProcessRunningState GetServiceProcessRunningState( |
- std::string* service_version_out) { |
+ std::string* service_version_out, base::ProcessId* pid_out) { |
std::string version; |
- GetServiceProcessSharedData(&version, NULL); |
- if (version.empty()) |
+ if (!GetServiceProcessSharedData(&version, pid_out)) |
return SERVICE_NOT_RUNNING; |
+#if defined(OS_POSIX) |
+ // We only need to check for service running on POSIX because Windows cleans |
+ // up shared memory files when an app crashes, so there isn't a chance of |
+ // us reading bogus data from shared memory for an app that has died. |
+ if (!CheckServiceProcessReady()) { |
+ return SERVICE_NOT_RUNNING; |
+ } |
+#endif // defined(OS_POSIX) |
+ |
// At this time we have a version string. Set the out param if it exists. |
if (service_version_out) |
*service_version_out = version; |
@@ -107,23 +95,22 @@ ServiceProcessRunningState GetServiceProcessRunningState( |
return SERVICE_SAME_VERSION_RUNNING; |
} |
- |
} // namespace |
// Return a name that is scoped to this instance of the service process. We |
-// use the user-data-dir as a scoping prefix. |
+// use the hash of the user-data-dir as a scoping prefix. We can't use |
+// the user-data-dir itself as we have limits on the size of the lock names. |
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()); |
+ std::string user_data_dir_path = WideToUTF8(user_data_dir.value()); |
#elif defined(OS_POSIX) |
- std::string scoped_name = user_data_dir.value(); |
+ std::string user_data_dir_path = 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; |
+ std::string hash = base::SHA1HashString(user_data_dir_path); |
+ std::string hex_hash = base::HexEncode(hash.c_str(), hash.length()); |
+ return hex_hash + "." + append_str; |
} |
// Return a name that is scoped to this instance of the service process. We |
@@ -143,16 +130,40 @@ std::string GetServiceProcessChannelName() { |
return GetServiceProcessScopedVersionedName("_service_ipc"); |
} |
-base::ProcessId GetServiceProcessPid() { |
- base::ProcessId pid = 0; |
- GetServiceProcessSharedData(NULL, &pid); |
- return pid; |
+// Reads the named shared memory to get the shared data. Returns false if no |
+// matching shared memory was found. |
+bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid) { |
+ scoped_ptr<base::SharedMemory> shared_mem_service_data; |
+ shared_mem_service_data.reset(new base::SharedMemory()); |
+ ServiceProcessSharedData* service_data = NULL; |
+ if (shared_mem_service_data.get() && |
+ shared_mem_service_data->Open(GetServiceProcessSharedMemName(), true) && |
+ shared_mem_service_data->Map(sizeof(ServiceProcessSharedData))) { |
+ service_data = reinterpret_cast<ServiceProcessSharedData*>( |
+ shared_mem_service_data->memory()); |
+ // Make sure the version in shared memory is null-terminated. If it is not, |
+ // treat it as invalid. |
+ if (version && memchr(service_data->service_process_version, '\0', |
+ sizeof(service_data->service_process_version))) |
+ *version = service_data->service_process_version; |
+ if (pid) |
+ *pid = service_data->service_process_pid; |
+ return true; |
+ } |
+ return false; |
} |
ServiceProcessState::ServiceProcessState() : state_(NULL) { |
} |
ServiceProcessState::~ServiceProcessState() { |
+ if (shared_mem_service_data_.get()) { |
+ // Delete needs a pool wrapped around it because it calls some Obj-C on Mac, |
+ // and since ServiceProcessState is a singleton, it gets destructed after |
+ // the standard NSAutoreleasePools have already been cleaned up. |
+ base::mac::ScopedNSAutoreleasePool pool; |
+ shared_mem_service_data_->Delete(GetServiceProcessSharedMemName()); |
+ } |
TearDownState(); |
} |
@@ -167,30 +178,26 @@ bool ServiceProcessState::Initialize() { |
} |
// Now that we have the singleton, take care of killing an older version, if |
// it exists. |
- if (ShouldHandleOtherVersion() && !HandleOtherVersion()) |
+ if (!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. |
+ // 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; |
+ base::ProcessId process_id; |
ServiceProcessRunningState state = |
- GetServiceProcessRunningState(&running_version); |
+ GetServiceProcessRunningState(&running_version, &process_id); |
switch (state) { |
case SERVICE_SAME_VERSION_RUNNING: |
case SERVICE_NEWER_VERSION_RUNNING: |
return false; |
case SERVICE_OLDER_VERSION_RUNNING: |
// If an older version is running, kill it. |
- ForceServiceProcessShutdown(running_version); |
+ ForceServiceProcessShutdown(running_version, process_id); |
break; |
case SERVICE_NOT_RUNNING: |
break; |
@@ -211,8 +218,8 @@ bool ServiceProcessState::CreateSharedData() { |
return false; |
} |
- scoped_ptr<base::SharedMemory> shared_mem_service_data; |
- shared_mem_service_data.reset(new base::SharedMemory()); |
+ scoped_ptr<base::SharedMemory> shared_mem_service_data( |
+ new base::SharedMemory()); |
if (!shared_mem_service_data.get()) |
return false; |
@@ -235,7 +242,11 @@ bool ServiceProcessState::CreateSharedData() { |
return true; |
} |
- |
std::string ServiceProcessState::GetAutoRunKey() { |
return GetServiceProcessScopedName("_service_run"); |
} |
+ |
+void ServiceProcessState::SignalStopped() { |
+ TearDownState(); |
+ shared_mem_service_data_.reset(); |
+} |