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 "tools/android/forwarder2/daemon.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <signal.h> 10 #include <sys/file.h> 11 #include <sys/stat.h> 12 #include <sys/types.h> 13 #include <sys/wait.h> 14 #include <unistd.h> 15 16 #include <cstdlib> 17 #include <cstring> 18 #include <string> 19 20 #include "base/basictypes.h" 21 #include "base/file_util.h" 22 #include "base/files/file_path.h" 23 #include "base/logging.h" 24 #include "base/memory/scoped_ptr.h" 25 #include "base/posix/eintr_wrapper.h" 26 #include "base/safe_strerror_posix.h" 27 #include "base/strings/string_number_conversions.h" 28 #include "base/strings/stringprintf.h" 29 #include "tools/android/forwarder2/common.h" 30 #include "tools/android/forwarder2/socket.h" 31 32 namespace forwarder2 { 33 namespace { 34 35 const int kBufferSize = 256; 36 37 // Timeout constant used for polling when connecting to the daemon's Unix Domain 38 // Socket and also when waiting for its death when it is killed. 39 const int kNumTries = 100; 40 const int kIdleTimeMSec = 20; 41 42 void InitLoggingForDaemon(const std::string& log_file) { 43 logging::LoggingSettings settings; 44 settings.logging_dest = 45 log_file.empty() ? 46 logging::LOG_TO_SYSTEM_DEBUG_LOG : logging::LOG_TO_FILE; 47 settings.log_file = log_file.c_str(); 48 settings.lock_log = logging::DONT_LOCK_LOG_FILE; 49 settings.dcheck_state = 50 logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS; 51 CHECK(logging::InitLogging(settings)); 52 } 53 54 bool RunServerAcceptLoop(const std::string& welcome_message, 55 Socket* server_socket, 56 Daemon::ServerDelegate* server_delegate) { 57 bool failed = false; 58 for (;;) { 59 scoped_ptr<Socket> client_socket(new Socket()); 60 if (!server_socket->Accept(client_socket.get())) { 61 if (server_socket->DidReceiveEvent()) 62 break; 63 PError("Accept()"); 64 failed = true; 65 break; 66 } 67 if (!client_socket->Write(welcome_message.c_str(), 68 welcome_message.length() + 1)) { 69 PError("Write()"); 70 failed = true; 71 continue; 72 } 73 server_delegate->OnClientConnected(client_socket.Pass()); 74 } 75 return !failed; 76 } 77 78 void SigChildHandler(int signal_number) { 79 DCHECK_EQ(signal_number, SIGCHLD); 80 int status; 81 pid_t child_pid = waitpid(-1 /* any child */, &status, WNOHANG); 82 if (child_pid < 0) { 83 PError("waitpid"); 84 return; 85 } 86 if (child_pid == 0) 87 return; 88 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 89 return; 90 // Avoid using StringAppendF() since it's unsafe in a signal handler due to 91 // its use of LOG(). 92 FixedSizeStringBuilder<256> string_builder; 93 string_builder.Append("Daemon (pid=%d) died unexpectedly with ", child_pid); 94 if (WIFEXITED(status)) 95 string_builder.Append("status %d.", WEXITSTATUS(status)); 96 else if (WIFSIGNALED(status)) 97 string_builder.Append("signal %d.", WTERMSIG(status)); 98 else 99 string_builder.Append("unknown reason."); 100 SIGNAL_SAFE_LOG(ERROR, string_builder.buffer()); 101 } 102 103 // Note that 0 is written to |lock_owner_pid| in case the file is not locked. 104 bool GetFileLockOwnerPid(int fd, pid_t* lock_owner_pid) { 105 struct flock lock_info = {}; 106 lock_info.l_type = F_WRLCK; 107 lock_info.l_whence = SEEK_CUR; 108 const int ret = HANDLE_EINTR(fcntl(fd, F_GETLK, &lock_info)); 109 if (ret < 0) { 110 if (errno == EBADF) { 111 // Assume that the provided file descriptor corresponding to the PID file 112 // was valid until the daemon removed this file. 113 *lock_owner_pid = 0; 114 return true; 115 } 116 PError("fcntl"); 117 return false; 118 } 119 if (lock_info.l_type == F_UNLCK) { 120 *lock_owner_pid = 0; 121 return true; 122 } 123 CHECK_EQ(F_WRLCK /* exclusive lock */, lock_info.l_type); 124 *lock_owner_pid = lock_info.l_pid; 125 return true; 126 } 127 128 scoped_ptr<Socket> ConnectToUnixDomainSocket( 129 const std::string& socket_name, 130 int tries_count, 131 int idle_time_msec, 132 const std::string& expected_welcome_message) { 133 for (int i = 0; i < tries_count; ++i) { 134 scoped_ptr<Socket> socket(new Socket()); 135 if (!socket->ConnectUnix(socket_name)) { 136 if (idle_time_msec) 137 usleep(idle_time_msec * 1000); 138 continue; 139 } 140 char buf[kBufferSize]; 141 DCHECK(expected_welcome_message.length() + 1 <= sizeof(buf)); 142 memset(buf, 0, sizeof(buf)); 143 if (socket->Read(buf, expected_welcome_message.length() + 1) < 0) { 144 perror("read"); 145 continue; 146 } 147 if (expected_welcome_message != buf) { 148 LOG(ERROR) << "Unexpected message read from daemon: " << buf; 149 break; 150 } 151 return socket.Pass(); 152 } 153 return scoped_ptr<Socket>(); 154 } 155 156 } // namespace 157 158 Daemon::Daemon(const std::string& log_file_path, 159 const std::string& identifier, 160 ClientDelegate* client_delegate, 161 ServerDelegate* server_delegate, 162 GetExitNotifierFDCallback get_exit_fd_callback) 163 : log_file_path_(log_file_path), 164 identifier_(identifier), 165 client_delegate_(client_delegate), 166 server_delegate_(server_delegate), 167 get_exit_fd_callback_(get_exit_fd_callback) { 168 DCHECK(client_delegate_); 169 DCHECK(server_delegate_); 170 DCHECK(get_exit_fd_callback_); 171 } 172 173 Daemon::~Daemon() {} 174 175 bool Daemon::SpawnIfNeeded() { 176 const int kSingleTry = 1; 177 const int kNoIdleTime = 0; 178 scoped_ptr<Socket> client_socket = ConnectToUnixDomainSocket( 179 identifier_, kSingleTry, kNoIdleTime, identifier_); 180 if (!client_socket) { 181 switch (fork()) { 182 case -1: 183 PError("fork()"); 184 return false; 185 // Child. 186 case 0: { 187 if (setsid() < 0) { // Detach the child process from its parent. 188 PError("setsid()"); 189 exit(1); 190 } 191 InitLoggingForDaemon(log_file_path_); 192 CloseFD(STDIN_FILENO); 193 CloseFD(STDOUT_FILENO); 194 CloseFD(STDERR_FILENO); 195 const int null_fd = open("/dev/null", O_RDWR); 196 CHECK_EQ(null_fd, STDIN_FILENO); 197 CHECK_EQ(dup(null_fd), STDOUT_FILENO); 198 CHECK_EQ(dup(null_fd), STDERR_FILENO); 199 Socket command_socket; 200 if (!command_socket.BindUnix(identifier_)) { 201 scoped_ptr<Socket> client_socket = ConnectToUnixDomainSocket( 202 identifier_, kSingleTry, kNoIdleTime, identifier_); 203 if (client_socket.get()) { 204 // The daemon was spawned by a concurrent process. 205 exit(0); 206 } 207 PError("bind()"); 208 exit(1); 209 } 210 server_delegate_->Init(); 211 command_socket.AddEventFd(get_exit_fd_callback_()); 212 return RunServerAcceptLoop( 213 identifier_, &command_socket, server_delegate_); 214 } 215 default: 216 break; 217 } 218 } 219 // Parent. 220 // Install the custom SIGCHLD handler. 221 sigset_t blocked_signals_set; 222 if (sigprocmask(0 /* first arg ignored */, NULL, &blocked_signals_set) < 0) { 223 PError("sigprocmask()"); 224 return false; 225 } 226 struct sigaction old_action; 227 struct sigaction new_action; 228 memset(&new_action, 0, sizeof(new_action)); 229 new_action.sa_handler = SigChildHandler; 230 new_action.sa_flags = SA_NOCLDSTOP; 231 sigemptyset(&new_action.sa_mask); 232 if (sigaction(SIGCHLD, &new_action, &old_action) < 0) { 233 PError("sigaction()"); 234 return false; 235 } 236 // Connect to the daemon's Unix Domain Socket. 237 bool failed = false; 238 if (!client_socket) { 239 client_socket = ConnectToUnixDomainSocket( 240 identifier_, kNumTries, kIdleTimeMSec, identifier_); 241 if (!client_socket) { 242 LOG(ERROR) << "Could not connect to daemon's Unix Daemon socket"; 243 failed = true; 244 } 245 } 246 if (!failed) 247 client_delegate_->OnDaemonReady(client_socket.get()); 248 // Restore the previous signal action for SIGCHLD. 249 if (sigaction(SIGCHLD, &old_action, NULL) < 0) { 250 PError("sigaction"); 251 failed = true; 252 } 253 return !failed; 254 } 255 256 bool Daemon::Kill() { 257 pid_t daemon_pid = Socket::GetUnixDomainSocketProcessOwner(identifier_); 258 if (daemon_pid < 0) 259 return true; // No daemon running. 260 if (kill(daemon_pid, SIGTERM) < 0) { 261 if (errno == ESRCH /* invalid PID */) 262 // The daemon exited for some reason (e.g. kill by a process other than 263 // us) right before the call to kill() above. 264 return true; 265 PError("kill"); 266 return false; 267 } 268 for (int i = 0; i < kNumTries; ++i) { 269 const pid_t previous_pid = daemon_pid; 270 daemon_pid = Socket::GetUnixDomainSocketProcessOwner(identifier_); 271 if (daemon_pid < 0) 272 return true; 273 // Since we are polling we might not see the 'daemon exited' event if 274 // another daemon was spawned during our idle period. 275 if (daemon_pid != previous_pid) { 276 LOG(WARNING) << "Daemon (pid=" << previous_pid 277 << ") was successfully killed but a new daemon (pid=" 278 << daemon_pid << ") seems to be running now."; 279 return true; 280 } 281 usleep(kIdleTimeMSec * 1000); 282 } 283 LOG(ERROR) << "Timed out while killing daemon. " 284 "It might still be tearing down."; 285 return false; 286 } 287 288 } // namespace forwarder2 289