service_process_util_posix.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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 3// found in the LICENSE file. 4 5#include "chrome/common/service_process_util.h" 6 7#include <signal.h> 8#include <unistd.h> 9 10#include "base/file_util.h" 11#include "base/logging.h" 12#include "base/message_loop.h" 13#include "base/message_loop_proxy.h" 14#include "base/message_pump_libevent.h" 15#include "base/path_service.h" 16#include "chrome/common/chrome_paths.h" 17#include "chrome/common/chrome_version_info.h" 18#include "chrome/common/multi_process_lock.h" 19 20namespace { 21 22int g_signal_socket = -1; 23 24// Gets the name of the lock file for service process. 25FilePath GetServiceProcessLockFilePath() { 26 FilePath user_data_dir; 27 PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); 28 chrome::VersionInfo version_info; 29 std::string lock_file_name = version_info.Version() + "Service Process Lock"; 30 return user_data_dir.Append(lock_file_name); 31} 32 33// Attempts to take a lock named |name|. If |waiting| is true then this will 34// make multiple attempts to acquire the lock. 35// Caller is responsible for ownership of the MultiProcessLock. 36MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) { 37 scoped_ptr<MultiProcessLock> lock(MultiProcessLock::Create(name)); 38 if (lock == NULL) return NULL; 39 bool got_lock = false; 40 for (int i = 0; i < 10; ++i) { 41 if (lock->TryLock()) { 42 got_lock = true; 43 break; 44 } 45 if (!waiting) break; 46 base::PlatformThread::Sleep(100 * i); 47 } 48 if (!got_lock) { 49 lock.reset(); 50 } 51 return lock.release(); 52} 53 54MultiProcessLock* TakeServiceRunningLock(bool waiting) { 55 std::string lock_name = 56 GetServiceProcessScopedName("_service_running"); 57 return TakeNamedLock(lock_name, waiting); 58} 59 60MultiProcessLock* TakeServiceInitializingLock(bool waiting) { 61 std::string lock_name = 62 GetServiceProcessScopedName("_service_initializing"); 63 return TakeNamedLock(lock_name, waiting); 64} 65 66} // namespace 67 68// Watches for |kShutDownMessage| to be written to the file descriptor it is 69// watching. When it reads |kShutDownMessage|, it performs |shutdown_task_|. 70// Used here to monitor the socket listening to g_signal_socket. 71class ServiceProcessShutdownMonitor 72 : public base::MessagePumpLibevent::Watcher { 73 public: 74 75 enum { 76 kShutDownMessage = 0xdecea5e 77 }; 78 79 explicit ServiceProcessShutdownMonitor(Task* shutdown_task) 80 : shutdown_task_(shutdown_task) { 81 } 82 83 virtual ~ServiceProcessShutdownMonitor(); 84 85 virtual void OnFileCanReadWithoutBlocking(int fd); 86 virtual void OnFileCanWriteWithoutBlocking(int fd); 87 88 private: 89 scoped_ptr<Task> shutdown_task_; 90}; 91 92ServiceProcessShutdownMonitor::~ServiceProcessShutdownMonitor() { 93} 94 95void ServiceProcessShutdownMonitor::OnFileCanReadWithoutBlocking(int fd) { 96 if (shutdown_task_.get()) { 97 int buffer; 98 int length = read(fd, &buffer, sizeof(buffer)); 99 if ((length == sizeof(buffer)) && (buffer == kShutDownMessage)) { 100 shutdown_task_->Run(); 101 shutdown_task_.reset(); 102 } else if (length > 0) { 103 LOG(ERROR) << "Unexpected read: " << buffer; 104 } else if (length == 0) { 105 LOG(ERROR) << "Unexpected fd close"; 106 } else if (length < 0) { 107 PLOG(ERROR) << "read"; 108 } 109 } 110} 111 112void ServiceProcessShutdownMonitor::OnFileCanWriteWithoutBlocking(int fd) { 113 NOTIMPLEMENTED(); 114} 115 116// "Forced" Shutdowns on POSIX are done via signals. The magic signal for 117// a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is 118// not, but we don't ever expect it to be called. 119static void SigTermHandler(int sig, siginfo_t* info, void* uap) { 120 // TODO(dmaclach): add security here to make sure that we are being shut 121 // down by an appropriate process. 122 int message = ServiceProcessShutdownMonitor::kShutDownMessage; 123 if (write(g_signal_socket, &message, sizeof(message)) < 0) { 124 PLOG(ERROR) << "write"; 125 } 126} 127 128// See comment for SigTermHandler. 129bool ForceServiceProcessShutdown(const std::string& version, 130 base::ProcessId process_id) { 131 if (kill(process_id, SIGTERM) < 0) { 132 PLOG(ERROR) << "kill"; 133 return false; 134 } 135 return true; 136} 137 138bool CheckServiceProcessReady() { 139 scoped_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock(false)); 140 return running_lock.get() == NULL; 141} 142 143struct ServiceProcessState::StateData 144 : public base::RefCountedThreadSafe<ServiceProcessState::StateData> { 145 scoped_ptr<MultiProcessLock> initializing_lock_; 146 scoped_ptr<MultiProcessLock> running_lock_; 147 scoped_ptr<ServiceProcessShutdownMonitor> shut_down_monitor_; 148 base::MessagePumpLibevent::FileDescriptorWatcher watcher_; 149 int sockets_[2]; 150 struct sigaction old_action_; 151 bool set_action_; 152 153 // WatchFileDescriptor needs to be set up by the thread that is going 154 // to be monitoring it. 155 void SignalReady() { 156 CHECK(MessageLoopForIO::current()->WatchFileDescriptor( 157 sockets_[0], true, MessageLoopForIO::WATCH_READ, 158 &watcher_, shut_down_monitor_.get())); 159 g_signal_socket = sockets_[1]; 160 161 // Set up signal handler for SIGTERM. 162 struct sigaction action; 163 action.sa_sigaction = SigTermHandler; 164 sigemptyset(&action.sa_mask); 165 action.sa_flags = SA_SIGINFO; 166 if (sigaction(SIGTERM, &action, &old_action_) == 0) { 167 // If the old_action is not default, somebody else has installed a 168 // a competing handler. Our handler is going to override it so it 169 // won't be called. If this occurs it needs to be fixed. 170 DCHECK_EQ(old_action_.sa_handler, SIG_DFL); 171 set_action_ = true; 172 initializing_lock_.reset(); 173 } else { 174 PLOG(ERROR) << "sigaction"; 175 } 176 } 177}; 178 179bool ServiceProcessState::TakeSingletonLock() { 180 CHECK(!state_); 181 state_ = new StateData; 182 state_->AddRef(); 183 state_->sockets_[0] = -1; 184 state_->sockets_[1] = -1; 185 state_->set_action_ = false; 186 state_->initializing_lock_.reset(TakeServiceInitializingLock(true)); 187 return state_->initializing_lock_.get(); 188} 189 190bool ServiceProcessState::SignalReady( 191 base::MessageLoopProxy* message_loop_proxy, Task* shutdown_task) { 192 CHECK(state_); 193 CHECK_EQ(g_signal_socket, -1); 194 195 state_->running_lock_.reset(TakeServiceRunningLock(true)); 196 if (state_->running_lock_.get() == NULL) { 197 return false; 198 } 199 state_->shut_down_monitor_.reset( 200 new ServiceProcessShutdownMonitor(shutdown_task)); 201 if (pipe(state_->sockets_) < 0) { 202 PLOG(ERROR) << "pipe"; 203 return false; 204 } 205 message_loop_proxy->PostTask(FROM_HERE, 206 NewRunnableMethod(state_, &ServiceProcessState::StateData::SignalReady)); 207 return true; 208} 209 210bool ServiceProcessState::AddToAutoRun() { 211 NOTIMPLEMENTED(); 212 return false; 213} 214 215bool ServiceProcessState::RemoveFromAutoRun() { 216 NOTIMPLEMENTED(); 217 return false; 218} 219 220void ServiceProcessState::TearDownState() { 221 g_signal_socket = -1; 222 if (state_) { 223 if (state_->sockets_[0] != -1) { 224 close(state_->sockets_[0]); 225 } 226 if (state_->sockets_[1] != -1) { 227 close(state_->sockets_[1]); 228 } 229 if (state_->set_action_) { 230 if (sigaction(SIGTERM, &state_->old_action_, NULL) < 0) { 231 PLOG(ERROR) << "sigaction"; 232 } 233 } 234 state_->Release(); 235 state_ = NULL; 236 } 237} 238