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

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 linux build 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
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 GetServiceProcessSharedData(&version, pid_out);
73 if (version.empty()) 53 if (version.empty())
74 return SERVICE_NOT_RUNNING; 54 return SERVICE_NOT_RUNNING;
75 55
76 // At this time we have a version string. Set the out param if it exists. 56 // At this time we have a version string. Set the out param if it exists.
77 if (service_version_out) 57 if (service_version_out)
78 *service_version_out = version; 58 *service_version_out = version;
79 59
80 scoped_ptr<Version> service_version(Version::GetVersionFromString(version)); 60 scoped_ptr<Version> service_version(Version::GetVersionFromString(version));
81 // If the version string is invalid, treat it like an older version. 61 // If the version string is invalid, treat it like an older version.
82 if (!service_version.get()) 62 if (!service_version.get())
(...skipping 21 matching lines...) Expand all
104 } else if (service_version->CompareTo(*running_version) > 0) { 84 } else if (service_version->CompareTo(*running_version) > 0) {
105 return SERVICE_NEWER_VERSION_RUNNING; 85 return SERVICE_NEWER_VERSION_RUNNING;
106 } 86 }
107 return SERVICE_SAME_VERSION_RUNNING; 87 return SERVICE_SAME_VERSION_RUNNING;
108 } 88 }
109 89
110 90
111 } // namespace 91 } // namespace
112 92
113 // Return a name that is scoped to this instance of the service process. We 93 // Return a name that is scoped to this instance of the service process. We
114 // use the user-data-dir as a scoping prefix. 94 // use the hash of the user-data-dir as a scoping prefix. We can't use
95 // 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) { 96 std::string GetServiceProcessScopedName(const std::string& append_str) {
116 FilePath user_data_dir; 97 FilePath user_data_dir;
117 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 98 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
118 #if defined(OS_WIN) 99 #if defined(OS_WIN)
119 std::string scoped_name = WideToUTF8(user_data_dir.value()); 100 std::string user_data_dir_path = WideToUTF8(user_data_dir.value());
120 #elif defined(OS_POSIX) 101 #elif defined(OS_POSIX)
121 std::string scoped_name = user_data_dir.value(); 102 std::string user_data_dir_path = user_data_dir.value();
122 #endif // defined(OS_WIN) 103 #endif // defined(OS_WIN)
123 std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!'); 104 std::string hash = base::SHA1HashString(user_data_dir_path);
124 std::replace(scoped_name.begin(), scoped_name.end(), '/', '!'); 105 std::string hex_hash = base::HexEncode(hash.c_str(), hash.length());
125 scoped_name.append(append_str); 106 return hex_hash + "." + append_str;
126 return scoped_name;
127 } 107 }
128 108
129 // Return a name that is scoped to this instance of the service process. We 109 // 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. 110 // use the user-data-dir and the version as a scoping prefix.
131 std::string GetServiceProcessScopedVersionedName( 111 std::string GetServiceProcessScopedVersionedName(
132 const std::string& append_str) { 112 const std::string& append_str) {
133 std::string versioned_str; 113 std::string versioned_str;
134 chrome::VersionInfo version_info; 114 chrome::VersionInfo version_info;
135 DCHECK(version_info.is_valid()); 115 DCHECK(version_info.is_valid());
136 versioned_str.append(version_info.Version()); 116 versioned_str.append(version_info.Version());
137 versioned_str.append(append_str); 117 versioned_str.append(append_str);
138 return GetServiceProcessScopedName(versioned_str); 118 return GetServiceProcessScopedName(versioned_str);
139 } 119 }
140 120
141 // Gets the name of the service process IPC channel. 121 // Gets the name of the service process IPC channel.
142 std::string GetServiceProcessChannelName() { 122 std::string GetServiceProcessChannelName() {
143 return GetServiceProcessScopedVersionedName("_service_ipc"); 123 return GetServiceProcessScopedVersionedName("_service_ipc");
144 } 124 }
145 125
146 base::ProcessId GetServiceProcessPid() { 126 // Reads the named shared memory to get the shared data. Returns false if no
147 base::ProcessId pid = 0; 127 // matching shared memory was found.
148 GetServiceProcessSharedData(NULL, &pid); 128 bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid) {
149 return pid; 129 scoped_ptr<base::SharedMemory> shared_mem_service_data;
Scott Byer 2011/02/02 00:12:38 Did this function need to get moved? It's not like
dmac 2011/02/02 00:56:25 Yes, I needed to take it out of the anonymous name
130 shared_mem_service_data.reset(new base::SharedMemory());
131 ServiceProcessSharedData* service_data = NULL;
132 if (shared_mem_service_data.get() &&
133 shared_mem_service_data->Open(GetServiceProcessSharedMemName(), true) &&
134 shared_mem_service_data->Map(sizeof(ServiceProcessSharedData))) {
135 service_data = reinterpret_cast<ServiceProcessSharedData*>(
136 shared_mem_service_data->memory());
137 // Make sure the version in shared memory is null-terminated. If it is not,
138 // treat it as invalid.
139 if (version && memchr(service_data->service_process_version, '\0',
140 sizeof(service_data->service_process_version)))
141 *version = service_data->service_process_version;
142 if (pid)
143 *pid = service_data->service_process_pid;
144 return true;
145 }
146 return false;
150 } 147 }
151 148
152 ServiceProcessState::ServiceProcessState() : state_(NULL) { 149 ServiceProcessState::ServiceProcessState() : state_(NULL) {
153 } 150 }
154 151
155 ServiceProcessState::~ServiceProcessState() { 152 ServiceProcessState::~ServiceProcessState() {
153 if (shared_mem_service_data_.get()) {
154 // Delete needs a pool wrapped around it because it call some obj-c on Mac.
155 base::mac::ScopedNSAutoreleasePool pool;
156 shared_mem_service_data_->Delete(GetServiceProcessSharedMemName());
157 }
156 TearDownState(); 158 TearDownState();
157 } 159 }
158 160
159 // static 161 // static
160 ServiceProcessState* ServiceProcessState::GetInstance() { 162 ServiceProcessState* ServiceProcessState::GetInstance() {
161 return Singleton<ServiceProcessState>::get(); 163 return Singleton<ServiceProcessState>::get();
162 } 164 }
163 165
164 bool ServiceProcessState::Initialize() { 166 bool ServiceProcessState::Initialize() {
165 if (!TakeSingletonLock()) { 167 if (!TakeSingletonLock()) {
166 return false; 168 return false;
167 } 169 }
168 // Now that we have the singleton, take care of killing an older version, if 170 // Now that we have the singleton, take care of killing an older version, if
169 // it exists. 171 // it exists.
170 if (ShouldHandleOtherVersion() && !HandleOtherVersion()) 172 if (ShouldHandleOtherVersion() && !HandleOtherVersion())
171 return false; 173 return false;
172 174
173 // TODO(sanjeevr): We can probably use the shared mem as the sole singleton 175 // TODO(sanjeevr): We can probably use the shared mem as the sole singleton
174 // mechanism. For that the shared mem class needs to return whether it created 176 // mechanism. For that the shared mem class needs to return whether it created
175 // new instance or opened an existing one. Also shared memory on Linux uses 177 // 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. 178 // a file on disk which is not deleted when the process exits.
177 179
178 // Now that we have the singleton, let is also write the version we are using 180 // 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. 181 // to shared memory. This can be used by a newer service to signal us to exit.
180 return CreateSharedData(); 182 return CreateSharedData();
181 } 183 }
182 184
183 bool ServiceProcessState::HandleOtherVersion() { 185 bool ServiceProcessState::HandleOtherVersion() {
184 std::string running_version; 186 std::string running_version;
187 base::ProcessId process_id;
185 ServiceProcessRunningState state = 188 ServiceProcessRunningState state =
186 GetServiceProcessRunningState(&running_version); 189 GetServiceProcessRunningState(&running_version, &process_id);
187 switch (state) { 190 switch (state) {
188 case SERVICE_SAME_VERSION_RUNNING: 191 case SERVICE_SAME_VERSION_RUNNING:
189 case SERVICE_NEWER_VERSION_RUNNING: 192 case SERVICE_NEWER_VERSION_RUNNING:
190 return false; 193 return false;
191 case SERVICE_OLDER_VERSION_RUNNING: 194 case SERVICE_OLDER_VERSION_RUNNING:
192 // If an older version is running, kill it. 195 // If an older version is running, kill it.
193 ForceServiceProcessShutdown(running_version); 196 ForceServiceProcessShutdown(running_version, process_id);
194 break; 197 break;
195 case SERVICE_NOT_RUNNING: 198 case SERVICE_NOT_RUNNING:
196 break; 199 break;
197 } 200 }
198 return true; 201 return true;
199 } 202 }
200 203
201 bool ServiceProcessState::CreateSharedData() { 204 bool ServiceProcessState::CreateSharedData() {
202 chrome::VersionInfo version_info; 205 chrome::VersionInfo version_info;
203 if (!version_info.is_valid()) { 206 if (!version_info.is_valid()) {
204 NOTREACHED() << "Failed to get current file version"; 207 NOTREACHED() << "Failed to get current file version";
205 return false; 208 return false;
206 } 209 }
207 if (version_info.Version().length() >= kMaxVersionStringLength) { 210 if (version_info.Version().length() >= kMaxVersionStringLength) {
208 NOTREACHED() << "Version string length is << " << 211 NOTREACHED() << "Version string length is << " <<
209 version_info.Version().length() << "which is longer than" << 212 version_info.Version().length() << "which is longer than" <<
210 kMaxVersionStringLength; 213 kMaxVersionStringLength;
211 return false; 214 return false;
212 } 215 }
213 216
214 scoped_ptr<base::SharedMemory> shared_mem_service_data; 217 scoped_ptr<base::SharedMemory> shared_mem_service_data(
215 shared_mem_service_data.reset(new base::SharedMemory()); 218 new base::SharedMemory());
216 if (!shared_mem_service_data.get()) 219 if (!shared_mem_service_data.get())
217 return false; 220 return false;
218 221
219 uint32 alloc_size = sizeof(ServiceProcessSharedData); 222 uint32 alloc_size = sizeof(ServiceProcessSharedData);
220 if (!shared_mem_service_data->CreateNamed(GetServiceProcessSharedMemName(), 223 if (!shared_mem_service_data->CreateNamed(GetServiceProcessSharedMemName(),
221 true, alloc_size)) 224 true, alloc_size))
222 return false; 225 return false;
223 226
224 if (!shared_mem_service_data->Map(alloc_size)) 227 if (!shared_mem_service_data->Map(alloc_size))
225 return false; 228 return false;
226 229
227 memset(shared_mem_service_data->memory(), 0, alloc_size); 230 memset(shared_mem_service_data->memory(), 0, alloc_size);
228 ServiceProcessSharedData* shared_data = 231 ServiceProcessSharedData* shared_data =
229 reinterpret_cast<ServiceProcessSharedData*>( 232 reinterpret_cast<ServiceProcessSharedData*>(
230 shared_mem_service_data->memory()); 233 shared_mem_service_data->memory());
231 memcpy(shared_data->service_process_version, version_info.Version().c_str(), 234 memcpy(shared_data->service_process_version, version_info.Version().c_str(),
232 version_info.Version().length()); 235 version_info.Version().length());
233 shared_data->service_process_pid = base::GetCurrentProcId(); 236 shared_data->service_process_pid = base::GetCurrentProcId();
234 shared_mem_service_data_.reset(shared_mem_service_data.release()); 237 shared_mem_service_data_.reset(shared_mem_service_data.release());
235 return true; 238 return true;
236 } 239 }
237 240
238
239 std::string ServiceProcessState::GetAutoRunKey() { 241 std::string ServiceProcessState::GetAutoRunKey() {
240 return GetServiceProcessScopedName("_service_run"); 242 return GetServiceProcessScopedName("_service_run");
241 } 243 }
244
245 void ServiceProcessState::SignalStopped() {
246 TearDownState();
247 shared_mem_service_data_.reset();
248 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698