Fix broken path in extensions/common/PRESUBMIT.py
[chromium-blink-merge.git] / chrome / common / service_process_util.cc
blobf9a990a4ad8e862e80731d9f89af931f5b5ebdba
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/common/service_process_util.h"
7 #include <algorithm>
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/memory/singleton.h"
12 #include "base/path_service.h"
13 #include "base/sha1.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/version.h"
19 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/chrome_paths.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/chrome_version_info.h"
23 #include "components/cloud_devices/common/cloud_devices_switches.h"
24 #include "content/public/common/content_paths.h"
25 #include "google_apis/gaia/gaia_switches.h"
26 #include "ui/base/ui_base_switches.h"
28 #if !defined(OS_MACOSX)
30 namespace {
32 // This should be more than enough to hold a version string assuming each part
33 // of the version string is an int64.
34 const uint32 kMaxVersionStringLength = 256;
36 // The structure that gets written to shared memory.
37 struct ServiceProcessSharedData {
38 char service_process_version[kMaxVersionStringLength];
39 base::ProcessId service_process_pid;
42 // Gets the name of the shared memory used by the service process to write its
43 // version. The name is not versioned.
44 std::string GetServiceProcessSharedMemName() {
45 return GetServiceProcessScopedName("_service_shmem");
48 enum ServiceProcessRunningState {
49 SERVICE_NOT_RUNNING,
50 SERVICE_OLDER_VERSION_RUNNING,
51 SERVICE_SAME_VERSION_RUNNING,
52 SERVICE_NEWER_VERSION_RUNNING,
55 ServiceProcessRunningState GetServiceProcessRunningState(
56 std::string* service_version_out, base::ProcessId* pid_out) {
57 std::string version;
58 if (!GetServiceProcessData(&version, pid_out))
59 return SERVICE_NOT_RUNNING;
61 #if defined(OS_POSIX)
62 // We only need to check for service running on POSIX because Windows cleans
63 // up shared memory files when an app crashes, so there isn't a chance of
64 // us reading bogus data from shared memory for an app that has died.
65 if (!CheckServiceProcessReady()) {
66 return SERVICE_NOT_RUNNING;
68 #endif // defined(OS_POSIX)
70 // At this time we have a version string. Set the out param if it exists.
71 if (service_version_out)
72 *service_version_out = version;
74 Version service_version(version);
75 // If the version string is invalid, treat it like an older version.
76 if (!service_version.IsValid())
77 return SERVICE_OLDER_VERSION_RUNNING;
79 // Get the version of the currently *running* instance of Chrome.
80 chrome::VersionInfo version_info;
81 Version running_version(version_info.Version());
82 if (!running_version.IsValid()) {
83 NOTREACHED() << "Failed to parse version info";
84 // Our own version is invalid. This is an error case. Pretend that we
85 // are out of date.
86 return SERVICE_NEWER_VERSION_RUNNING;
89 if (running_version.CompareTo(service_version) > 0) {
90 return SERVICE_OLDER_VERSION_RUNNING;
91 } else if (service_version.CompareTo(running_version) > 0) {
92 return SERVICE_NEWER_VERSION_RUNNING;
94 return SERVICE_SAME_VERSION_RUNNING;
97 } // namespace
100 // Return a name that is scoped to this instance of the service process. We
101 // use the user-data-dir and the version as a scoping prefix.
102 std::string GetServiceProcessScopedVersionedName(
103 const std::string& append_str) {
104 std::string versioned_str;
105 chrome::VersionInfo version_info;
106 versioned_str.append(version_info.Version());
107 versioned_str.append(append_str);
108 return GetServiceProcessScopedName(versioned_str);
111 // Reads the named shared memory to get the shared data. Returns false if no
112 // matching shared memory was found.
113 bool GetServiceProcessData(std::string* version, base::ProcessId* pid) {
114 scoped_ptr<base::SharedMemory> shared_mem_service_data;
115 shared_mem_service_data.reset(new base::SharedMemory());
116 ServiceProcessSharedData* service_data = NULL;
117 if (shared_mem_service_data.get() &&
118 shared_mem_service_data->Open(GetServiceProcessSharedMemName(), true) &&
119 shared_mem_service_data->Map(sizeof(ServiceProcessSharedData))) {
120 service_data = reinterpret_cast<ServiceProcessSharedData*>(
121 shared_mem_service_data->memory());
122 // Make sure the version in shared memory is null-terminated. If it is not,
123 // treat it as invalid.
124 if (version && memchr(service_data->service_process_version, '\0',
125 sizeof(service_data->service_process_version)))
126 *version = service_data->service_process_version;
127 if (pid)
128 *pid = service_data->service_process_pid;
129 return true;
131 return false;
134 #endif // !OS_MACOSX
136 // Return a name that is scoped to this instance of the service process. We
137 // use the hash of the user-data-dir as a scoping prefix. We can't use
138 // the user-data-dir itself as we have limits on the size of the lock names.
139 std::string GetServiceProcessScopedName(const std::string& append_str) {
140 base::FilePath user_data_dir;
141 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
142 #if defined(OS_WIN)
143 std::string user_data_dir_path = base::WideToUTF8(user_data_dir.value());
144 #elif defined(OS_POSIX)
145 std::string user_data_dir_path = user_data_dir.value();
146 #endif // defined(OS_WIN)
147 std::string hash = base::SHA1HashString(user_data_dir_path);
148 std::string hex_hash = base::HexEncode(hash.c_str(), hash.length());
149 return hex_hash + "." + append_str;
152 scoped_ptr<base::CommandLine> CreateServiceProcessCommandLine() {
153 base::FilePath exe_path;
154 PathService::Get(content::CHILD_PROCESS_EXE, &exe_path);
155 DCHECK(!exe_path.empty()) << "Unable to get service process binary name.";
156 scoped_ptr<base::CommandLine> command_line(new base::CommandLine(exe_path));
157 command_line->AppendSwitchASCII(switches::kProcessType,
158 switches::kServiceProcess);
159 static const char* const kSwitchesToCopy[] = {
160 switches::kCloudPrintSetupProxy,
161 switches::kCloudPrintURL,
162 switches::kCloudPrintXmppEndpoint,
163 #if defined(OS_WIN)
164 switches::kEnableCloudPrintXps,
165 #endif
166 switches::kEnableLogging,
167 switches::kIgnoreUrlFetcherCertRequests,
168 switches::kLang,
169 switches::kLoggingLevel,
170 switches::kLsoUrl,
171 switches::kNoServiceAutorun,
172 switches::kUserDataDir,
173 switches::kV,
174 switches::kVModule,
175 switches::kWaitForDebugger,
178 command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
179 kSwitchesToCopy,
180 arraysize(kSwitchesToCopy));
181 return command_line.Pass();
184 ServiceProcessState::ServiceProcessState() : state_(NULL) {
185 autorun_command_line_ = CreateServiceProcessCommandLine();
186 CreateState();
189 ServiceProcessState::~ServiceProcessState() {
190 #if !defined(OS_MACOSX)
191 if (shared_mem_service_data_.get()) {
192 shared_mem_service_data_->Delete(GetServiceProcessSharedMemName());
194 #endif // !OS_MACOSX
195 TearDownState();
198 void ServiceProcessState::SignalStopped() {
199 TearDownState();
200 shared_mem_service_data_.reset();
203 #if !defined(OS_MACOSX)
204 bool ServiceProcessState::Initialize() {
205 if (!TakeSingletonLock()) {
206 return false;
208 // Now that we have the singleton, take care of killing an older version, if
209 // it exists.
210 if (!HandleOtherVersion())
211 return false;
213 // Write the version we are using to shared memory. This can be used by a
214 // newer service to signal us to exit.
215 return CreateSharedData();
218 bool ServiceProcessState::HandleOtherVersion() {
219 std::string running_version;
220 base::ProcessId process_id = 0;
221 ServiceProcessRunningState state =
222 GetServiceProcessRunningState(&running_version, &process_id);
223 switch (state) {
224 case SERVICE_SAME_VERSION_RUNNING:
225 case SERVICE_NEWER_VERSION_RUNNING:
226 return false;
227 case SERVICE_OLDER_VERSION_RUNNING:
228 // If an older version is running, kill it.
229 ForceServiceProcessShutdown(running_version, process_id);
230 break;
231 case SERVICE_NOT_RUNNING:
232 break;
234 return true;
237 bool ServiceProcessState::CreateSharedData() {
238 chrome::VersionInfo version_info;
239 if (version_info.Version().length() >= kMaxVersionStringLength) {
240 NOTREACHED() << "Version string length is << " <<
241 version_info.Version().length() << "which is longer than" <<
242 kMaxVersionStringLength;
243 return false;
246 scoped_ptr<base::SharedMemory> shared_mem_service_data(
247 new base::SharedMemory());
248 if (!shared_mem_service_data.get())
249 return false;
251 uint32 alloc_size = sizeof(ServiceProcessSharedData);
252 // TODO(viettrungluu): Named shared memory is deprecated (crbug.com/345734).
253 if (!shared_mem_service_data->CreateNamedDeprecated
254 (GetServiceProcessSharedMemName(), true, alloc_size))
255 return false;
257 if (!shared_mem_service_data->Map(alloc_size))
258 return false;
260 memset(shared_mem_service_data->memory(), 0, alloc_size);
261 ServiceProcessSharedData* shared_data =
262 reinterpret_cast<ServiceProcessSharedData*>(
263 shared_mem_service_data->memory());
264 memcpy(shared_data->service_process_version, version_info.Version().c_str(),
265 version_info.Version().length());
266 shared_data->service_process_pid = base::GetCurrentProcId();
267 shared_mem_service_data_.reset(shared_mem_service_data.release());
268 return true;
271 IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() {
272 return ::GetServiceProcessChannel();
275 #endif // !OS_MACOSX