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

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

Powered by Google App Engine
This is Rietveld 408576698