Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / common / service_process_util.cc
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.
4
5 #include "chrome/common/service_process_util.h"
6
7 #include <algorithm>
8
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"
27
28 #if !defined(OS_MACOSX)
29
30 namespace {
31
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;
35
36 // The structure that gets written to shared memory.
37 struct ServiceProcessSharedData {
38   char service_process_version[kMaxVersionStringLength];
39   base::ProcessId service_process_pid;
40 };
41
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");
46 }
47
48 enum ServiceProcessRunningState {
49   SERVICE_NOT_RUNNING,
50   SERVICE_OLDER_VERSION_RUNNING,
51   SERVICE_SAME_VERSION_RUNNING,
52   SERVICE_NEWER_VERSION_RUNNING,
53 };
54
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;
60
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;
67   }
68 #endif  // defined(OS_POSIX)
69
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;
73
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;
78
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;
87   }
88
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;
93   }
94   return SERVICE_SAME_VERSION_RUNNING;
95 }
96
97 }  // namespace
98
99 // Return a name that is scoped to this instance of the service process. We
100 // use the hash of the user-data-dir as a scoping prefix. We can't use
101 // the user-data-dir itself as we have limits on the size of the lock names.
102 std::string GetServiceProcessScopedName(const std::string& append_str) {
103   base::FilePath user_data_dir;
104   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
105 #if defined(OS_WIN)
106   std::string user_data_dir_path = base::WideToUTF8(user_data_dir.value());
107 #elif defined(OS_POSIX)
108   std::string user_data_dir_path = user_data_dir.value();
109 #endif  // defined(OS_WIN)
110   std::string hash = base::SHA1HashString(user_data_dir_path);
111   std::string hex_hash = base::HexEncode(hash.c_str(), hash.length());
112   return hex_hash + "." + append_str;
113 }
114
115 // Return a name that is scoped to this instance of the service process. We
116 // use the user-data-dir and the version as a scoping prefix.
117 std::string GetServiceProcessScopedVersionedName(
118     const std::string& append_str) {
119   std::string versioned_str;
120   chrome::VersionInfo version_info;
121   versioned_str.append(version_info.Version());
122   versioned_str.append(append_str);
123   return GetServiceProcessScopedName(versioned_str);
124 }
125
126 // Reads the named shared memory to get the shared data. Returns false if no
127 // matching shared memory was found.
128 bool GetServiceProcessData(std::string* version, base::ProcessId* pid) {
129   scoped_ptr<base::SharedMemory> shared_mem_service_data;
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;
147 }
148
149 #endif  // !OS_MACOSX
150
151 scoped_ptr<base::CommandLine> CreateServiceProcessCommandLine() {
152   base::FilePath exe_path;
153   PathService::Get(content::CHILD_PROCESS_EXE, &exe_path);
154   DCHECK(!exe_path.empty()) << "Unable to get service process binary name.";
155   scoped_ptr<base::CommandLine> command_line(new base::CommandLine(exe_path));
156   command_line->AppendSwitchASCII(switches::kProcessType,
157                                   switches::kServiceProcess);
158   static const char* const kSwitchesToCopy[] = {
159     switches::kCloudPrintSetupProxy,
160     switches::kCloudPrintURL,
161     switches::kCloudPrintXmppEndpoint,
162 #if defined(OS_WIN)
163     switches::kEnableCloudPrintXps,
164 #endif
165     switches::kEnableLogging,
166     switches::kIgnoreUrlFetcherCertRequests,
167     switches::kLang,
168     switches::kLoggingLevel,
169     switches::kLsoUrl,
170     switches::kNoServiceAutorun,
171     switches::kUserDataDir,
172     switches::kV,
173     switches::kVModule,
174     switches::kWaitForDebugger,
175   };
176
177   command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
178                                  kSwitchesToCopy,
179                                  arraysize(kSwitchesToCopy));
180   return command_line.Pass();
181 }
182
183 ServiceProcessState::ServiceProcessState() : state_(NULL) {
184   autorun_command_line_ = CreateServiceProcessCommandLine();
185   CreateState();
186 }
187
188 ServiceProcessState::~ServiceProcessState() {
189 #if !defined(OS_MACOSX)
190   if (shared_mem_service_data_.get()) {
191     shared_mem_service_data_->Delete(GetServiceProcessSharedMemName());
192   }
193 #endif  // !OS_MACOSX
194   TearDownState();
195 }
196
197 void ServiceProcessState::SignalStopped() {
198   TearDownState();
199   shared_mem_service_data_.reset();
200 }
201
202 #if !defined(OS_MACOSX)
203 bool ServiceProcessState::Initialize() {
204   if (!TakeSingletonLock()) {
205     return false;
206   }
207   // Now that we have the singleton, take care of killing an older version, if
208   // it exists.
209   if (!HandleOtherVersion())
210     return false;
211
212   // Write the version we are using to shared memory. This can be used by a
213   // newer service to signal us to exit.
214   return CreateSharedData();
215 }
216
217 bool ServiceProcessState::HandleOtherVersion() {
218   std::string running_version;
219   base::ProcessId process_id = 0;
220   ServiceProcessRunningState state =
221       GetServiceProcessRunningState(&running_version, &process_id);
222   switch (state) {
223     case SERVICE_SAME_VERSION_RUNNING:
224     case SERVICE_NEWER_VERSION_RUNNING:
225       return false;
226     case SERVICE_OLDER_VERSION_RUNNING:
227       // If an older version is running, kill it.
228       ForceServiceProcessShutdown(running_version, process_id);
229       break;
230     case SERVICE_NOT_RUNNING:
231       break;
232   }
233   return true;
234 }
235
236 bool ServiceProcessState::CreateSharedData() {
237   chrome::VersionInfo version_info;
238   if (version_info.Version().length() >= kMaxVersionStringLength) {
239     NOTREACHED() << "Version string length is << " <<
240         version_info.Version().length() << "which is longer than" <<
241         kMaxVersionStringLength;
242     return false;
243   }
244
245   scoped_ptr<base::SharedMemory> shared_mem_service_data(
246       new base::SharedMemory());
247   if (!shared_mem_service_data.get())
248     return false;
249
250   uint32 alloc_size = sizeof(ServiceProcessSharedData);
251   // TODO(viettrungluu): Named shared memory is deprecated (crbug.com/345734).
252   if (!shared_mem_service_data->CreateNamedDeprecated
253           (GetServiceProcessSharedMemName(), true, alloc_size))
254     return false;
255
256   if (!shared_mem_service_data->Map(alloc_size))
257     return false;
258
259   memset(shared_mem_service_data->memory(), 0, alloc_size);
260   ServiceProcessSharedData* shared_data =
261       reinterpret_cast<ServiceProcessSharedData*>(
262           shared_mem_service_data->memory());
263   memcpy(shared_data->service_process_version, version_info.Version().c_str(),
264          version_info.Version().length());
265   shared_data->service_process_pid = base::GetCurrentProcId();
266   shared_mem_service_data_.reset(shared_mem_service_data.release());
267   return true;
268 }
269
270 IPC::ChannelHandle ServiceProcessState::GetServiceProcessChannel() {
271   return ::GetServiceProcessChannel();
272 }
273
274 #endif  // !OS_MACOSX