Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(530)

Side by Side Diff: chrome/common/service_process_util.cc

Issue 6349029: Get service processes working on Mac and Linux. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix up small typo in comment Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/common/service_process_util.h ('k') | chrome/common/service_process_util_posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <algorithm> 5 #include <algorithm>
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/mac/scoped_nsautorelease_pool.h"
9 #include "base/path_service.h" 10 #include "base/path_service.h"
10 #include "base/process_util.h" 11 #include "base/process_util.h"
12 #include "base/sha1.h"
11 #include "base/singleton.h" 13 #include "base/singleton.h"
12 #include "base/string16.h" 14 #include "base/string16.h"
15 #include "base/string_number_conversions.h"
13 #include "base/string_util.h" 16 #include "base/string_util.h"
14 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
15 #include "base/version.h" 18 #include "base/version.h"
16 #include "chrome/common/chrome_constants.h" 19 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/chrome_paths.h" 20 #include "chrome/common/chrome_paths.h"
18 #include "chrome/common/chrome_version_info.h" 21 #include "chrome/common/chrome_version_info.h"
19 #include "chrome/common/service_process_util.h" 22 #include "chrome/common/service_process_util.h"
20 23
21 namespace { 24 namespace {
22 25
23 // This should be more than enough to hold a version string assuming each part 26 // This should be more than enough to hold a version string assuming each part
24 // of the version string is an int64. 27 // of the version string is an int64.
25 const uint32 kMaxVersionStringLength = 256; 28 const uint32 kMaxVersionStringLength = 256;
26 29
27 // The structure that gets written to shared memory. 30 // The structure that gets written to shared memory.
28 struct ServiceProcessSharedData { 31 struct ServiceProcessSharedData {
29 char service_process_version[kMaxVersionStringLength]; 32 char service_process_version[kMaxVersionStringLength];
30 base::ProcessId service_process_pid; 33 base::ProcessId service_process_pid;
31 }; 34 };
32 35
33 // Gets the name of the shared memory used by the service process to write its 36 // Gets the name of the shared memory used by the service process to write its
34 // version. The name is not versioned. 37 // version. The name is not versioned.
35 std::string GetServiceProcessSharedMemName() { 38 std::string GetServiceProcessSharedMemName() {
36 return GetServiceProcessScopedName("_service_shmem"); 39 return GetServiceProcessScopedName("_service_shmem");
37 } 40 }
38 41
39 // Reads the named shared memory to get the shared data. Returns false if no
40 // matching shared memory was found.
41 bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid) {
42 scoped_ptr<base::SharedMemory> shared_mem_service_data;
43 shared_mem_service_data.reset(new base::SharedMemory());
44 ServiceProcessSharedData* service_data = NULL;
45 if (shared_mem_service_data.get() &&
46 shared_mem_service_data->Open(GetServiceProcessSharedMemName(), true) &&
47 shared_mem_service_data->Map(sizeof(ServiceProcessSharedData))) {
48 service_data = reinterpret_cast<ServiceProcessSharedData*>(
49 shared_mem_service_data->memory());
50 // Make sure the version in shared memory is null-terminated. If it is not,
51 // treat it as invalid.
52 if (version && memchr(service_data->service_process_version, '\0',
53 sizeof(service_data->service_process_version)))
54 *version = service_data->service_process_version;
55 if (pid)
56 *pid = service_data->service_process_pid;
57 return true;
58 }
59 return false;
60 }
61
62 enum ServiceProcessRunningState { 42 enum ServiceProcessRunningState {
63 SERVICE_NOT_RUNNING, 43 SERVICE_NOT_RUNNING,
64 SERVICE_OLDER_VERSION_RUNNING, 44 SERVICE_OLDER_VERSION_RUNNING,
65 SERVICE_SAME_VERSION_RUNNING, 45 SERVICE_SAME_VERSION_RUNNING,
66 SERVICE_NEWER_VERSION_RUNNING, 46 SERVICE_NEWER_VERSION_RUNNING,
67 }; 47 };
68 48
69 ServiceProcessRunningState GetServiceProcessRunningState( 49 ServiceProcessRunningState GetServiceProcessRunningState(
70 std::string* service_version_out) { 50 std::string* service_version_out, base::ProcessId* pid_out) {
71 std::string version; 51 std::string version;
72 GetServiceProcessSharedData(&version, NULL); 52 if (!GetServiceProcessSharedData(&version, pid_out))
73 if (version.empty())
74 return SERVICE_NOT_RUNNING; 53 return SERVICE_NOT_RUNNING;
75 54
55 #if defined(OS_POSIX)
56 // We only need to check for service running on POSIX because Windows cleans
57 // up shared memory files when an app crashes, so there isn't a chance of
58 // us reading bogus data from shared memory for an app that has died.
59 if (!CheckServiceProcessReady()) {
60 return SERVICE_NOT_RUNNING;
61 }
62 #endif // defined(OS_POSIX)
63
76 // At this time we have a version string. Set the out param if it exists. 64 // At this time we have a version string. Set the out param if it exists.
77 if (service_version_out) 65 if (service_version_out)
78 *service_version_out = version; 66 *service_version_out = version;
79 67
80 scoped_ptr<Version> service_version(Version::GetVersionFromString(version)); 68 scoped_ptr<Version> service_version(Version::GetVersionFromString(version));
81 // If the version string is invalid, treat it like an older version. 69 // If the version string is invalid, treat it like an older version.
82 if (!service_version.get()) 70 if (!service_version.get())
83 return SERVICE_OLDER_VERSION_RUNNING; 71 return SERVICE_OLDER_VERSION_RUNNING;
84 72
85 // Get the version of the currently *running* instance of Chrome. 73 // Get the version of the currently *running* instance of Chrome.
(...skipping 14 matching lines...) Expand all
100 } 88 }
101 89
102 if (running_version->CompareTo(*service_version) > 0) { 90 if (running_version->CompareTo(*service_version) > 0) {
103 return SERVICE_OLDER_VERSION_RUNNING; 91 return SERVICE_OLDER_VERSION_RUNNING;
104 } else if (service_version->CompareTo(*running_version) > 0) { 92 } else if (service_version->CompareTo(*running_version) > 0) {
105 return SERVICE_NEWER_VERSION_RUNNING; 93 return SERVICE_NEWER_VERSION_RUNNING;
106 } 94 }
107 return SERVICE_SAME_VERSION_RUNNING; 95 return SERVICE_SAME_VERSION_RUNNING;
108 } 96 }
109 97
110
111 } // namespace 98 } // namespace
112 99
113 // Return a name that is scoped to this instance of the service process. We 100 // Return a name that is scoped to this instance of the service process. We
114 // use the user-data-dir as a scoping prefix. 101 // use the hash of the user-data-dir as a scoping prefix. We can't use
102 // the user-data-dir itself as we have limits on the size of the lock names.
115 std::string GetServiceProcessScopedName(const std::string& append_str) { 103 std::string GetServiceProcessScopedName(const std::string& append_str) {
116 FilePath user_data_dir; 104 FilePath user_data_dir;
117 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 105 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
118 #if defined(OS_WIN) 106 #if defined(OS_WIN)
119 std::string scoped_name = WideToUTF8(user_data_dir.value()); 107 std::string user_data_dir_path = WideToUTF8(user_data_dir.value());
120 #elif defined(OS_POSIX) 108 #elif defined(OS_POSIX)
121 std::string scoped_name = user_data_dir.value(); 109 std::string user_data_dir_path = user_data_dir.value();
122 #endif // defined(OS_WIN) 110 #endif // defined(OS_WIN)
123 std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!'); 111 std::string hash = base::SHA1HashString(user_data_dir_path);
124 std::replace(scoped_name.begin(), scoped_name.end(), '/', '!'); 112 std::string hex_hash = base::HexEncode(hash.c_str(), hash.length());
125 scoped_name.append(append_str); 113 return hex_hash + "." + append_str;
126 return scoped_name;
127 } 114 }
128 115
129 // Return a name that is scoped to this instance of the service process. We 116 // Return a name that is scoped to this instance of the service process. We
130 // use the user-data-dir and the version as a scoping prefix. 117 // use the user-data-dir and the version as a scoping prefix.
131 std::string GetServiceProcessScopedVersionedName( 118 std::string GetServiceProcessScopedVersionedName(
132 const std::string& append_str) { 119 const std::string& append_str) {
133 std::string versioned_str; 120 std::string versioned_str;
134 chrome::VersionInfo version_info; 121 chrome::VersionInfo version_info;
135 DCHECK(version_info.is_valid()); 122 DCHECK(version_info.is_valid());
136 versioned_str.append(version_info.Version()); 123 versioned_str.append(version_info.Version());
137 versioned_str.append(append_str); 124 versioned_str.append(append_str);
138 return GetServiceProcessScopedName(versioned_str); 125 return GetServiceProcessScopedName(versioned_str);
139 } 126 }
140 127
141 // Gets the name of the service process IPC channel. 128 // Gets the name of the service process IPC channel.
142 std::string GetServiceProcessChannelName() { 129 std::string GetServiceProcessChannelName() {
143 return GetServiceProcessScopedVersionedName("_service_ipc"); 130 return GetServiceProcessScopedVersionedName("_service_ipc");
144 } 131 }
145 132
146 base::ProcessId GetServiceProcessPid() { 133 // Reads the named shared memory to get the shared data. Returns false if no
147 base::ProcessId pid = 0; 134 // matching shared memory was found.
148 GetServiceProcessSharedData(NULL, &pid); 135 bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid) {
149 return pid; 136 scoped_ptr<base::SharedMemory> shared_mem_service_data;
137 shared_mem_service_data.reset(new base::SharedMemory());
138 ServiceProcessSharedData* service_data = NULL;
139 if (shared_mem_service_data.get() &&
140 shared_mem_service_data->Open(GetServiceProcessSharedMemName(), true) &&
141 shared_mem_service_data->Map(sizeof(ServiceProcessSharedData))) {
142 service_data = reinterpret_cast<ServiceProcessSharedData*>(
143 shared_mem_service_data->memory());
144 // Make sure the version in shared memory is null-terminated. If it is not,
145 // treat it as invalid.
146 if (version && memchr(service_data->service_process_version, '\0',
147 sizeof(service_data->service_process_version)))
148 *version = service_data->service_process_version;
149 if (pid)
150 *pid = service_data->service_process_pid;
151 return true;
152 }
153 return false;
150 } 154 }
151 155
152 ServiceProcessState::ServiceProcessState() : state_(NULL) { 156 ServiceProcessState::ServiceProcessState() : state_(NULL) {
153 } 157 }
154 158
155 ServiceProcessState::~ServiceProcessState() { 159 ServiceProcessState::~ServiceProcessState() {
160 if (shared_mem_service_data_.get()) {
161 // Delete needs a pool wrapped around it because it calls some Obj-C on Mac,
162 // and since ServiceProcessState is a singleton, it gets destructed after
163 // the standard NSAutoreleasePools have already been cleaned up.
164 base::mac::ScopedNSAutoreleasePool pool;
165 shared_mem_service_data_->Delete(GetServiceProcessSharedMemName());
166 }
156 TearDownState(); 167 TearDownState();
157 } 168 }
158 169
159 // static 170 // static
160 ServiceProcessState* ServiceProcessState::GetInstance() { 171 ServiceProcessState* ServiceProcessState::GetInstance() {
161 return Singleton<ServiceProcessState>::get(); 172 return Singleton<ServiceProcessState>::get();
162 } 173 }
163 174
164 bool ServiceProcessState::Initialize() { 175 bool ServiceProcessState::Initialize() {
165 if (!TakeSingletonLock()) { 176 if (!TakeSingletonLock()) {
166 return false; 177 return false;
167 } 178 }
168 // Now that we have the singleton, take care of killing an older version, if 179 // Now that we have the singleton, take care of killing an older version, if
169 // it exists. 180 // it exists.
170 if (ShouldHandleOtherVersion() && !HandleOtherVersion()) 181 if (!HandleOtherVersion())
171 return false; 182 return false;
172 183
173 // TODO(sanjeevr): We can probably use the shared mem as the sole singleton 184 // Write the version we are using to shared memory. This can be used by a
174 // mechanism. For that the shared mem class needs to return whether it created 185 // newer service to signal us to exit.
175 // new instance or opened an existing one. Also shared memory on Linux uses
176 // a file on disk which is not deleted when the process exits.
177
178 // Now that we have the singleton, let is also write the version we are using
179 // to shared memory. This can be used by a newer service to signal us to exit.
180 return CreateSharedData(); 186 return CreateSharedData();
181 } 187 }
182 188
183 bool ServiceProcessState::HandleOtherVersion() { 189 bool ServiceProcessState::HandleOtherVersion() {
184 std::string running_version; 190 std::string running_version;
191 base::ProcessId process_id;
185 ServiceProcessRunningState state = 192 ServiceProcessRunningState state =
186 GetServiceProcessRunningState(&running_version); 193 GetServiceProcessRunningState(&running_version, &process_id);
187 switch (state) { 194 switch (state) {
188 case SERVICE_SAME_VERSION_RUNNING: 195 case SERVICE_SAME_VERSION_RUNNING:
189 case SERVICE_NEWER_VERSION_RUNNING: 196 case SERVICE_NEWER_VERSION_RUNNING:
190 return false; 197 return false;
191 case SERVICE_OLDER_VERSION_RUNNING: 198 case SERVICE_OLDER_VERSION_RUNNING:
192 // If an older version is running, kill it. 199 // If an older version is running, kill it.
193 ForceServiceProcessShutdown(running_version); 200 ForceServiceProcessShutdown(running_version, process_id);
194 break; 201 break;
195 case SERVICE_NOT_RUNNING: 202 case SERVICE_NOT_RUNNING:
196 break; 203 break;
197 } 204 }
198 return true; 205 return true;
199 } 206 }
200 207
201 bool ServiceProcessState::CreateSharedData() { 208 bool ServiceProcessState::CreateSharedData() {
202 chrome::VersionInfo version_info; 209 chrome::VersionInfo version_info;
203 if (!version_info.is_valid()) { 210 if (!version_info.is_valid()) {
204 NOTREACHED() << "Failed to get current file version"; 211 NOTREACHED() << "Failed to get current file version";
205 return false; 212 return false;
206 } 213 }
207 if (version_info.Version().length() >= kMaxVersionStringLength) { 214 if (version_info.Version().length() >= kMaxVersionStringLength) {
208 NOTREACHED() << "Version string length is << " << 215 NOTREACHED() << "Version string length is << " <<
209 version_info.Version().length() << "which is longer than" << 216 version_info.Version().length() << "which is longer than" <<
210 kMaxVersionStringLength; 217 kMaxVersionStringLength;
211 return false; 218 return false;
212 } 219 }
213 220
214 scoped_ptr<base::SharedMemory> shared_mem_service_data; 221 scoped_ptr<base::SharedMemory> shared_mem_service_data(
215 shared_mem_service_data.reset(new base::SharedMemory()); 222 new base::SharedMemory());
216 if (!shared_mem_service_data.get()) 223 if (!shared_mem_service_data.get())
217 return false; 224 return false;
218 225
219 uint32 alloc_size = sizeof(ServiceProcessSharedData); 226 uint32 alloc_size = sizeof(ServiceProcessSharedData);
220 if (!shared_mem_service_data->CreateNamed(GetServiceProcessSharedMemName(), 227 if (!shared_mem_service_data->CreateNamed(GetServiceProcessSharedMemName(),
221 true, alloc_size)) 228 true, alloc_size))
222 return false; 229 return false;
223 230
224 if (!shared_mem_service_data->Map(alloc_size)) 231 if (!shared_mem_service_data->Map(alloc_size))
225 return false; 232 return false;
226 233
227 memset(shared_mem_service_data->memory(), 0, alloc_size); 234 memset(shared_mem_service_data->memory(), 0, alloc_size);
228 ServiceProcessSharedData* shared_data = 235 ServiceProcessSharedData* shared_data =
229 reinterpret_cast<ServiceProcessSharedData*>( 236 reinterpret_cast<ServiceProcessSharedData*>(
230 shared_mem_service_data->memory()); 237 shared_mem_service_data->memory());
231 memcpy(shared_data->service_process_version, version_info.Version().c_str(), 238 memcpy(shared_data->service_process_version, version_info.Version().c_str(),
232 version_info.Version().length()); 239 version_info.Version().length());
233 shared_data->service_process_pid = base::GetCurrentProcId(); 240 shared_data->service_process_pid = base::GetCurrentProcId();
234 shared_mem_service_data_.reset(shared_mem_service_data.release()); 241 shared_mem_service_data_.reset(shared_mem_service_data.release());
235 return true; 242 return true;
236 } 243 }
237 244
238
239 std::string ServiceProcessState::GetAutoRunKey() { 245 std::string ServiceProcessState::GetAutoRunKey() {
240 return GetServiceProcessScopedName("_service_run"); 246 return GetServiceProcessScopedName("_service_run");
241 } 247 }
248
249 void ServiceProcessState::SignalStopped() {
250 TearDownState();
251 shared_mem_service_data_.reset();
252 }
OLDNEW
« no previous file with comments | « chrome/common/service_process_util.h ('k') | chrome/common/service_process_util_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698