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

Side by Side Diff: tools/android/forwarder2/daemon.cc

Issue 11360248: Use the new forwarder2's Daemon implementation in device_forwarder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address David's comments Created 8 years 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
« no previous file with comments | « tools/android/forwarder2/daemon.h ('k') | tools/android/forwarder2/device_controller.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 "tools/android/forwarder2/daemon.h" 5 #include "tools/android/forwarder2/daemon.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <signal.h> 9 #include <signal.h>
10 #include <stdio.h>
11 #include <sys/file.h> 10 #include <sys/file.h>
12 #include <sys/stat.h> 11 #include <sys/stat.h>
13 #include <sys/types.h> 12 #include <sys/types.h>
14 #include <sys/wait.h> 13 #include <sys/wait.h>
15 #include <unistd.h> 14 #include <unistd.h>
16 15
16 #include <cstdlib>
17 #include <cstring>
17 #include <string> 18 #include <string>
18 19
19 #include "base/basictypes.h" 20 #include "base/basictypes.h"
20 #include "base/file_path.h" 21 #include "base/file_path.h"
21 #include "base/file_util.h" 22 #include "base/file_util.h"
22 #include "base/logging.h" 23 #include "base/logging.h"
24 #include "base/memory/scoped_ptr.h"
23 #include "base/posix/eintr_wrapper.h" 25 #include "base/posix/eintr_wrapper.h"
24 #include "base/safe_strerror_posix.h" 26 #include "base/safe_strerror_posix.h"
25 #include "base/string_number_conversions.h" 27 #include "base/string_number_conversions.h"
26 #include "base/stringprintf.h" 28 #include "base/stringprintf.h"
27 #include "tools/android/forwarder2/common.h" 29 #include "tools/android/forwarder2/common.h"
30 #include "tools/android/forwarder2/socket.h"
28 31
29 namespace forwarder2 { 32 namespace forwarder2 {
30 namespace { 33 namespace {
31 34
32 const char kLogFilePath[] = "/tmp/host_forwarder_log"; 35 const int kBufferSize = 256;
33 36
34 class FileDescriptorAutoCloser { 37 class FileDescriptorAutoCloser {
35 public: 38 public:
36 explicit FileDescriptorAutoCloser(int fd) : fd_(fd) { 39 explicit FileDescriptorAutoCloser(int fd) : fd_(fd) {
37 DCHECK(fd_ >= 0); 40 DCHECK(fd_ >= 0);
38 } 41 }
39 42
40 ~FileDescriptorAutoCloser() { 43 ~FileDescriptorAutoCloser() {
41 if (fd_ > -1) 44 if (fd_ > -1)
42 CloseFD(fd_); 45 CloseFD(fd_);
43 } 46 }
44 47
45 int Release() { 48 int Release() {
46 const int fd = fd_; 49 const int fd = fd_;
47 fd_ = -1; 50 fd_ = -1;
48 return fd; 51 return fd;
49 } 52 }
50 53
51 private: 54 private:
52 int fd_; 55 int fd_;
53 56
54 DISALLOW_COPY_AND_ASSIGN(FileDescriptorAutoCloser); 57 DISALLOW_COPY_AND_ASSIGN(FileDescriptorAutoCloser);
55 }; 58 };
56 59
57 // Handles creation and destruction of the PID file. 60 void InitLoggingForDaemon(const std::string& log_file) {
58 class PIDFile { 61 CHECK(
59 public: 62 logging::InitLogging(
60 static scoped_ptr<PIDFile> Create(const std::string& path) { 63 log_file.c_str(),
61 scoped_ptr<PIDFile> pid_file; 64 log_file.empty() ?
62 const int pid_file_fd = HANDLE_EINTR( 65 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG : logging::LOG_ONLY_TO_FILE,
63 open(path.c_str(), O_CREAT | O_WRONLY, 0600)); 66 logging::DONT_LOCK_LOG_FILE, logging::APPEND_TO_OLD_LOG_FILE,
64 if (pid_file_fd < 0) { 67 logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS));
65 PError("open()");
66 return pid_file.Pass();
67 }
68 FileDescriptorAutoCloser fd_closer(pid_file_fd);
69 struct flock lock_info = {};
70 lock_info.l_type = F_WRLCK;
71 lock_info.l_whence = SEEK_CUR;
72 if (HANDLE_EINTR(fcntl(pid_file_fd, F_SETLK, &lock_info)) < 0) {
73 if (errno == EAGAIN || errno == EACCES) {
74 LOG(ERROR) << "Daemon already running (PID file already locked)";
75 return pid_file.Pass();
76 }
77 PError("lockf()");
78 return pid_file.Pass();
79 }
80 const std::string pid_string = base::StringPrintf("%d\n", getpid());
81 CHECK(HANDLE_EINTR(write(pid_file_fd, pid_string.c_str(),
82 pid_string.length())));
83 pid_file.reset(new PIDFile(fd_closer.Release(), path));
84 return pid_file.Pass();
85 }
86
87 ~PIDFile() {
88 CloseFD(fd_); // This also releases the lock.
89 if (remove(path_.c_str()) < 0)
90 PError("remove");
91 }
92
93 private:
94 PIDFile(int fd, const std::string& path) : fd_(fd), path_(path) {
95 DCHECK(fd_ >= 0);
96 }
97
98 const int fd_;
99 const std::string path_;
100
101 DISALLOW_COPY_AND_ASSIGN(PIDFile);
102 };
103
104 // Takes ownership of |data|.
105 void ReleaseDaemonResourcesAtExit(void* data) {
106 DCHECK(data);
107 delete reinterpret_cast<PIDFile*>(data);
108 } 68 }
109 69
110 void InitLogging(const char* log_file) { 70 bool RunServerAcceptLoop(const std::string& welcome_message,
111 CHECK( 71 Socket* server_socket,
112 logging::InitLogging( 72 Daemon::ServerDelegate* server_delegate) {
113 log_file, 73 bool failed = false;
114 logging::LOG_ONLY_TO_FILE, 74 for (;;) {
115 logging::DONT_LOCK_LOG_FILE, 75 scoped_ptr<Socket> client_socket(new Socket());
116 logging::APPEND_TO_OLD_LOG_FILE, 76 if (!server_socket->Accept(client_socket.get())) {
117 logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS)); 77 if (server_socket->exited())
78 break;
79 PError("Accept()");
80 failed = true;
81 break;
82 }
83 if (!client_socket->Write(welcome_message.c_str(),
84 welcome_message.length() + 1)) {
85 PError("Write()");
86 failed = true;
87 continue;
88 }
89 server_delegate->OnClientConnected(client_socket.Pass());
90 }
91 server_delegate->OnServerExited();
92 return !failed;
118 } 93 }
119 94
120 void SigChildHandler(int signal_number) { 95 void SigChildHandler(int signal_number) {
121 DCHECK_EQ(signal_number, SIGCHLD); 96 DCHECK_EQ(signal_number, SIGCHLD);
97 SIGNAL_SAFE_LOG(ERROR, "Caught unexpected SIGCHLD");
122 // The daemon should not terminate while its parent is still running. 98 // The daemon should not terminate while its parent is still running.
123 int status; 99 int status;
124 pid_t child_pid = waitpid(-1 /* any child */, &status, WNOHANG); 100 pid_t child_pid = waitpid(-1 /* any child */, &status, WNOHANG);
125 if (child_pid < 0) { 101 if (child_pid < 0) {
126 PError("waitpid"); 102 PError("waitpid");
127 return; 103 return;
128 } 104 }
129 if (child_pid == 0) 105 if (child_pid == 0)
130 return; 106 return;
131 // Avoid using StringAppendF() since it's unsafe in a signal handler due to 107 // Avoid using StringAppendF() since it's unsafe in a signal handler due to
(...skipping 27 matching lines...) Expand all
159 } 135 }
160 if (lock_info.l_type == F_UNLCK) { 136 if (lock_info.l_type == F_UNLCK) {
161 *lock_owner_pid = 0; 137 *lock_owner_pid = 0;
162 return true; 138 return true;
163 } 139 }
164 CHECK_EQ(F_WRLCK /* exclusive lock */, lock_info.l_type); 140 CHECK_EQ(F_WRLCK /* exclusive lock */, lock_info.l_type);
165 *lock_owner_pid = lock_info.l_pid; 141 *lock_owner_pid = lock_info.l_pid;
166 return true; 142 return true;
167 } 143 }
168 144
145 scoped_ptr<Socket> ConnectToUnixDomainSocket(
146 const std::string& socket_name,
147 int tries_count,
148 int idle_time_msec,
149 const std::string& expected_welcome_message) {
150 for (int i = 0; i < tries_count; ++i) {
151 scoped_ptr<Socket> socket(new Socket());
152 if (!socket->ConnectUnix(socket_name, true)) {
153 if (idle_time_msec)
154 usleep(idle_time_msec * 1000);
155 continue;
156 }
157 char buf[kBufferSize];
158 DCHECK(expected_welcome_message.length() + 1 <= sizeof(buf));
159 memset(buf, 0, sizeof(buf));
160 if (socket->Read(buf, sizeof(buf)) < 0) {
161 perror("read");
162 continue;
163 }
164 if (expected_welcome_message != buf) {
165 LOG(ERROR) << "Unexpected message read from daemon: " << buf;
166 break;
167 }
168 return socket.Pass();
169 }
170 return scoped_ptr<Socket>(NULL);
171 }
172
169 } // namespace 173 } // namespace
170 174
171 Daemon::Daemon(const std::string& pid_file_path) 175 // Handles creation and destruction of the PID file.
172 : pid_file_path_(pid_file_path) { 176 class Daemon::PIDFile {
177 public:
178 static scoped_ptr<PIDFile> Create(const std::string& path) {
179 scoped_ptr<PIDFile> pid_file;
180 const int pid_file_fd = HANDLE_EINTR(
181 open(path.c_str(), O_CREAT | O_WRONLY, 0600));
182 if (pid_file_fd < 0) {
183 PError("open()");
184 return pid_file.Pass();
185 }
186 FileDescriptorAutoCloser fd_closer(pid_file_fd);
187 struct flock lock_info = {};
188 lock_info.l_type = F_WRLCK;
189 lock_info.l_whence = SEEK_CUR;
190 if (HANDLE_EINTR(fcntl(pid_file_fd, F_SETLK, &lock_info)) < 0) {
191 if (errno == EAGAIN || errno == EACCES) {
192 LOG(ERROR) << "Daemon already running (PID file already locked)";
193 return pid_file.Pass();
194 }
195 PError("lockf()");
196 return pid_file.Pass();
197 }
198 const std::string pid_string = base::StringPrintf("%d\n", getpid());
199 CHECK(HANDLE_EINTR(write(pid_file_fd, pid_string.c_str(),
200 pid_string.length())));
201 pid_file.reset(new PIDFile(fd_closer.Release(), path));
202 return pid_file.Pass();
203 }
204
205 ~PIDFile() {
206 CloseFD(fd_); // This also releases the lock.
207 if (remove(path_.c_str()) < 0)
208 PError("remove");
209 }
210
211 private:
212 PIDFile(int fd, const std::string& path) : fd_(fd), path_(path) {
213 DCHECK(fd_ >= 0);
214 }
215
216 const int fd_;
217 const std::string path_;
218
219 DISALLOW_COPY_AND_ASSIGN(PIDFile);
220 };
221
222 Daemon::Daemon(const std::string& log_file_path,
223 const std::string& pid_file_path,
224 const std::string& identifier,
225 ClientDelegate* client_delegate,
226 ServerDelegate* server_delegate,
227 GetExitNotifierFDCallback get_exit_fd_callback)
228 : log_file_path_(log_file_path),
229 pid_file_path_(pid_file_path),
230 identifier_(identifier),
231 client_delegate_(client_delegate),
232 server_delegate_(server_delegate),
233 get_exit_fd_callback_(get_exit_fd_callback) {
234 DCHECK(client_delegate_);
235 DCHECK(server_delegate_);
236 DCHECK(get_exit_fd_callback_);
173 } 237 }
174 238
175 bool Daemon::Spawn(bool* is_daemon) { 239 Daemon::~Daemon() {}
176 switch (fork()) { 240
177 case -1: 241 bool Daemon::SpawnIfNeeded() {
178 *is_daemon = false; 242 const int kSingleTry = 1;
179 PError("fork()"); 243 const int kNoIdleTime = 0;
180 return false; 244 scoped_ptr<Socket> client_socket = ConnectToUnixDomainSocket(
181 case 0: { // Child. 245 identifier_, kSingleTry, kNoIdleTime, identifier_);
182 *is_daemon = true; 246 if (!client_socket) {
183 scoped_ptr<PIDFile> pid_file = PIDFile::Create(pid_file_path_); 247 switch (fork()) {
184 if (!pid_file) 248 case -1:
249 PError("fork()");
185 return false; 250 return false;
186 base::AtExitManager::RegisterCallback( 251 // Child.
187 &ReleaseDaemonResourcesAtExit, pid_file.release()); 252 case 0: {
188 if (setsid() < 0) { // Detach the child process from its parent. 253 DCHECK(!pid_file_);
189 PError("setsid"); 254 pid_file_ = PIDFile::Create(pid_file_path_);
190 return false; 255 if (!pid_file_)
256 exit(1);
257 if (setsid() < 0) { // Detach the child process from its parent.
258 PError("setsid()");
259 exit(1);
260 }
261 InitLoggingForDaemon(log_file_path_);
262 CloseFD(STDIN_FILENO);
263 CloseFD(STDOUT_FILENO);
264 CloseFD(STDERR_FILENO);
265 const int null_fd = open("/dev/null", O_RDWR);
266 CHECK_EQ(null_fd, STDIN_FILENO);
267 CHECK_EQ(dup(null_fd), STDOUT_FILENO);
268 CHECK_EQ(dup(null_fd), STDERR_FILENO);
269 Socket command_socket;
270 if (!command_socket.BindUnix(identifier_, true)) {
271 PError("bind()");
272 exit(1);
273 }
274 server_delegate_->Init();
275 command_socket.set_exit_notifier_fd(get_exit_fd_callback_());
276 exit(!RunServerAcceptLoop(identifier_, &command_socket,
277 server_delegate_));
191 } 278 }
192 CloseFD(STDOUT_FILENO); 279 default:
193 CloseFD(STDERR_FILENO); 280 break;
194 InitLogging(kLogFilePath);
195 break;
196 } 281 }
197 default: // Parent.
198 *is_daemon = false;
199 signal(SIGCHLD, SigChildHandler);
200 } 282 }
201 return true; 283 // Parent.
284 // Install the custom SIGCHLD handler.
285 sigset_t blocked_signals_set;
286 if (sigprocmask(0 /* first arg ignored */, NULL, &blocked_signals_set) < 0) {
287 PError("sigprocmask()");
288 return false;
289 }
290 struct sigaction old_action;
291 struct sigaction new_action;
292 memset(&new_action, 0, sizeof(new_action));
293 new_action.sa_handler = SigChildHandler;
294 new_action.sa_flags = SA_NOCLDSTOP;
295 sigemptyset(&new_action.sa_mask);
296 if (sigaction(SIGCHLD, &new_action, &old_action) < 0) {
297 PError("sigaction()");
298 return false;
299 }
300 // Connect to the daemon's Unix Domain Socket.
301 bool failed = false;
302 if (!client_socket) {
303 const int kConnectTries = 20;
304 const int kConnectIdleTimeMSec = 10;
305 client_socket = ConnectToUnixDomainSocket(
306 identifier_, kConnectTries, kConnectIdleTimeMSec, identifier_);
307 if (!client_socket) {
308 LOG(ERROR) << "Could not connect to daemon's Unix Daemon socket";
309 failed = true;
310 }
311 }
312 if (!failed)
313 client_delegate_->OnDaemonReady(client_socket.get());
314 // Restore the previous signal action for SIGCHLD.
315 if (sigaction(SIGCHLD, &old_action, NULL) < 0) {
316 PError("sigaction");
317 failed = true;
318 }
319 return !failed;
202 } 320 }
203 321
204 bool Daemon::Kill() { 322 bool Daemon::Kill() {
205 int pid_file_fd = HANDLE_EINTR(open(pid_file_path_.c_str(), O_WRONLY)); 323 int pid_file_fd = HANDLE_EINTR(open(pid_file_path_.c_str(), O_WRONLY));
206 if (pid_file_fd < 0) { 324 if (pid_file_fd < 0) {
207 if (errno == ENOENT) 325 if (errno == ENOENT)
208 return true; 326 return true;
209 LOG(ERROR) << "Could not open " << pid_file_path_ << " in write mode: " 327 LOG(ERROR) << "Could not open " << pid_file_path_ << " in write mode: "
210 << safe_strerror(errno); 328 << safe_strerror(errno);
211 return false; 329 return false;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 return true; 365 return true;
248 } 366 }
249 usleep(kIdleTimeMS * 1000); 367 usleep(kIdleTimeMS * 1000);
250 } 368 }
251 LOG(ERROR) << "Timed out while killing daemon. " 369 LOG(ERROR) << "Timed out while killing daemon. "
252 "It might still be tearing down."; 370 "It might still be tearing down.";
253 return false; 371 return false;
254 } 372 }
255 373
256 } // namespace forwarder2 374 } // namespace forwarder2
OLDNEW
« no previous file with comments | « tools/android/forwarder2/daemon.h ('k') | tools/android/forwarder2/device_controller.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698