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

Unified 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, 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/android/forwarder2/daemon.h ('k') | tools/android/forwarder2/device_controller.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/android/forwarder2/daemon.cc
diff --git a/tools/android/forwarder2/daemon.cc b/tools/android/forwarder2/daemon.cc
index 2928f8f627f7c778c08857a09def4e6442bf76f3..5bdf936aa9cd2085f62edf16b5fa6e0280297e9f 100644
--- a/tools/android/forwarder2/daemon.cc
+++ b/tools/android/forwarder2/daemon.cc
@@ -7,29 +7,32 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
-#include <stdio.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <cstdlib>
+#include <cstring>
#include <string>
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "base/safe_strerror_posix.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "tools/android/forwarder2/common.h"
+#include "tools/android/forwarder2/socket.h"
namespace forwarder2 {
namespace {
-const char kLogFilePath[] = "/tmp/host_forwarder_log";
+const int kBufferSize = 256;
class FileDescriptorAutoCloser {
public:
@@ -54,71 +57,44 @@ class FileDescriptorAutoCloser {
DISALLOW_COPY_AND_ASSIGN(FileDescriptorAutoCloser);
};
-// Handles creation and destruction of the PID file.
-class PIDFile {
- public:
- static scoped_ptr<PIDFile> Create(const std::string& path) {
- scoped_ptr<PIDFile> pid_file;
- const int pid_file_fd = HANDLE_EINTR(
- open(path.c_str(), O_CREAT | O_WRONLY, 0600));
- if (pid_file_fd < 0) {
- PError("open()");
- return pid_file.Pass();
- }
- FileDescriptorAutoCloser fd_closer(pid_file_fd);
- struct flock lock_info = {};
- lock_info.l_type = F_WRLCK;
- lock_info.l_whence = SEEK_CUR;
- if (HANDLE_EINTR(fcntl(pid_file_fd, F_SETLK, &lock_info)) < 0) {
- if (errno == EAGAIN || errno == EACCES) {
- LOG(ERROR) << "Daemon already running (PID file already locked)";
- return pid_file.Pass();
- }
- PError("lockf()");
- return pid_file.Pass();
- }
- const std::string pid_string = base::StringPrintf("%d\n", getpid());
- CHECK(HANDLE_EINTR(write(pid_file_fd, pid_string.c_str(),
- pid_string.length())));
- pid_file.reset(new PIDFile(fd_closer.Release(), path));
- return pid_file.Pass();
- }
-
- ~PIDFile() {
- CloseFD(fd_); // This also releases the lock.
- if (remove(path_.c_str()) < 0)
- PError("remove");
- }
-
- private:
- PIDFile(int fd, const std::string& path) : fd_(fd), path_(path) {
- DCHECK(fd_ >= 0);
- }
-
- const int fd_;
- const std::string path_;
-
- DISALLOW_COPY_AND_ASSIGN(PIDFile);
-};
-
-// Takes ownership of |data|.
-void ReleaseDaemonResourcesAtExit(void* data) {
- DCHECK(data);
- delete reinterpret_cast<PIDFile*>(data);
-}
-
-void InitLogging(const char* log_file) {
+void InitLoggingForDaemon(const std::string& log_file) {
CHECK(
logging::InitLogging(
- log_file,
- logging::LOG_ONLY_TO_FILE,
- logging::DONT_LOCK_LOG_FILE,
- logging::APPEND_TO_OLD_LOG_FILE,
+ log_file.c_str(),
+ log_file.empty() ?
+ logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG : logging::LOG_ONLY_TO_FILE,
+ logging::DONT_LOCK_LOG_FILE, logging::APPEND_TO_OLD_LOG_FILE,
logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS));
}
+bool RunServerAcceptLoop(const std::string& welcome_message,
+ Socket* server_socket,
+ Daemon::ServerDelegate* server_delegate) {
+ bool failed = false;
+ for (;;) {
+ scoped_ptr<Socket> client_socket(new Socket());
+ if (!server_socket->Accept(client_socket.get())) {
+ if (server_socket->exited())
+ break;
+ PError("Accept()");
+ failed = true;
+ break;
+ }
+ if (!client_socket->Write(welcome_message.c_str(),
+ welcome_message.length() + 1)) {
+ PError("Write()");
+ failed = true;
+ continue;
+ }
+ server_delegate->OnClientConnected(client_socket.Pass());
+ }
+ server_delegate->OnServerExited();
+ return !failed;
+}
+
void SigChildHandler(int signal_number) {
DCHECK_EQ(signal_number, SIGCHLD);
+ SIGNAL_SAFE_LOG(ERROR, "Caught unexpected SIGCHLD");
// The daemon should not terminate while its parent is still running.
int status;
pid_t child_pid = waitpid(-1 /* any child */, &status, WNOHANG);
@@ -166,39 +142,181 @@ bool GetFileLockOwnerPid(int fd, pid_t* lock_owner_pid) {
return true;
}
+scoped_ptr<Socket> ConnectToUnixDomainSocket(
+ const std::string& socket_name,
+ int tries_count,
+ int idle_time_msec,
+ const std::string& expected_welcome_message) {
+ for (int i = 0; i < tries_count; ++i) {
+ scoped_ptr<Socket> socket(new Socket());
+ if (!socket->ConnectUnix(socket_name, true)) {
+ if (idle_time_msec)
+ usleep(idle_time_msec * 1000);
+ continue;
+ }
+ char buf[kBufferSize];
+ DCHECK(expected_welcome_message.length() + 1 <= sizeof(buf));
+ memset(buf, 0, sizeof(buf));
+ if (socket->Read(buf, sizeof(buf)) < 0) {
+ perror("read");
+ continue;
+ }
+ if (expected_welcome_message != buf) {
+ LOG(ERROR) << "Unexpected message read from daemon: " << buf;
+ break;
+ }
+ return socket.Pass();
+ }
+ return scoped_ptr<Socket>(NULL);
+}
+
} // namespace
-Daemon::Daemon(const std::string& pid_file_path)
- : pid_file_path_(pid_file_path) {
+// Handles creation and destruction of the PID file.
+class Daemon::PIDFile {
+ public:
+ static scoped_ptr<PIDFile> Create(const std::string& path) {
+ scoped_ptr<PIDFile> pid_file;
+ const int pid_file_fd = HANDLE_EINTR(
+ open(path.c_str(), O_CREAT | O_WRONLY, 0600));
+ if (pid_file_fd < 0) {
+ PError("open()");
+ return pid_file.Pass();
+ }
+ FileDescriptorAutoCloser fd_closer(pid_file_fd);
+ struct flock lock_info = {};
+ lock_info.l_type = F_WRLCK;
+ lock_info.l_whence = SEEK_CUR;
+ if (HANDLE_EINTR(fcntl(pid_file_fd, F_SETLK, &lock_info)) < 0) {
+ if (errno == EAGAIN || errno == EACCES) {
+ LOG(ERROR) << "Daemon already running (PID file already locked)";
+ return pid_file.Pass();
+ }
+ PError("lockf()");
+ return pid_file.Pass();
+ }
+ const std::string pid_string = base::StringPrintf("%d\n", getpid());
+ CHECK(HANDLE_EINTR(write(pid_file_fd, pid_string.c_str(),
+ pid_string.length())));
+ pid_file.reset(new PIDFile(fd_closer.Release(), path));
+ return pid_file.Pass();
+ }
+
+ ~PIDFile() {
+ CloseFD(fd_); // This also releases the lock.
+ if (remove(path_.c_str()) < 0)
+ PError("remove");
+ }
+
+ private:
+ PIDFile(int fd, const std::string& path) : fd_(fd), path_(path) {
+ DCHECK(fd_ >= 0);
+ }
+
+ const int fd_;
+ const std::string path_;
+
+ DISALLOW_COPY_AND_ASSIGN(PIDFile);
+};
+
+Daemon::Daemon(const std::string& log_file_path,
+ const std::string& pid_file_path,
+ const std::string& identifier,
+ ClientDelegate* client_delegate,
+ ServerDelegate* server_delegate,
+ GetExitNotifierFDCallback get_exit_fd_callback)
+ : log_file_path_(log_file_path),
+ pid_file_path_(pid_file_path),
+ identifier_(identifier),
+ client_delegate_(client_delegate),
+ server_delegate_(server_delegate),
+ get_exit_fd_callback_(get_exit_fd_callback) {
+ DCHECK(client_delegate_);
+ DCHECK(server_delegate_);
+ DCHECK(get_exit_fd_callback_);
}
-bool Daemon::Spawn(bool* is_daemon) {
- switch (fork()) {
- case -1:
- *is_daemon = false;
- PError("fork()");
- return false;
- case 0: { // Child.
- *is_daemon = true;
- scoped_ptr<PIDFile> pid_file = PIDFile::Create(pid_file_path_);
- if (!pid_file)
- return false;
- base::AtExitManager::RegisterCallback(
- &ReleaseDaemonResourcesAtExit, pid_file.release());
- if (setsid() < 0) { // Detach the child process from its parent.
- PError("setsid");
+Daemon::~Daemon() {}
+
+bool Daemon::SpawnIfNeeded() {
+ const int kSingleTry = 1;
+ const int kNoIdleTime = 0;
+ scoped_ptr<Socket> client_socket = ConnectToUnixDomainSocket(
+ identifier_, kSingleTry, kNoIdleTime, identifier_);
+ if (!client_socket) {
+ switch (fork()) {
+ case -1:
+ PError("fork()");
return false;
+ // Child.
+ case 0: {
+ DCHECK(!pid_file_);
+ pid_file_ = PIDFile::Create(pid_file_path_);
+ if (!pid_file_)
+ exit(1);
+ if (setsid() < 0) { // Detach the child process from its parent.
+ PError("setsid()");
+ exit(1);
+ }
+ InitLoggingForDaemon(log_file_path_);
+ CloseFD(STDIN_FILENO);
+ CloseFD(STDOUT_FILENO);
+ CloseFD(STDERR_FILENO);
+ const int null_fd = open("/dev/null", O_RDWR);
+ CHECK_EQ(null_fd, STDIN_FILENO);
+ CHECK_EQ(dup(null_fd), STDOUT_FILENO);
+ CHECK_EQ(dup(null_fd), STDERR_FILENO);
+ Socket command_socket;
+ if (!command_socket.BindUnix(identifier_, true)) {
+ PError("bind()");
+ exit(1);
+ }
+ server_delegate_->Init();
+ command_socket.set_exit_notifier_fd(get_exit_fd_callback_());
+ exit(!RunServerAcceptLoop(identifier_, &command_socket,
+ server_delegate_));
}
- CloseFD(STDOUT_FILENO);
- CloseFD(STDERR_FILENO);
- InitLogging(kLogFilePath);
- break;
+ default:
+ break;
}
- default: // Parent.
- *is_daemon = false;
- signal(SIGCHLD, SigChildHandler);
}
- return true;
+ // Parent.
+ // Install the custom SIGCHLD handler.
+ sigset_t blocked_signals_set;
+ if (sigprocmask(0 /* first arg ignored */, NULL, &blocked_signals_set) < 0) {
+ PError("sigprocmask()");
+ return false;
+ }
+ struct sigaction old_action;
+ struct sigaction new_action;
+ memset(&new_action, 0, sizeof(new_action));
+ new_action.sa_handler = SigChildHandler;
+ new_action.sa_flags = SA_NOCLDSTOP;
+ sigemptyset(&new_action.sa_mask);
+ if (sigaction(SIGCHLD, &new_action, &old_action) < 0) {
+ PError("sigaction()");
+ return false;
+ }
+ // Connect to the daemon's Unix Domain Socket.
+ bool failed = false;
+ if (!client_socket) {
+ const int kConnectTries = 20;
+ const int kConnectIdleTimeMSec = 10;
+ client_socket = ConnectToUnixDomainSocket(
+ identifier_, kConnectTries, kConnectIdleTimeMSec, identifier_);
+ if (!client_socket) {
+ LOG(ERROR) << "Could not connect to daemon's Unix Daemon socket";
+ failed = true;
+ }
+ }
+ if (!failed)
+ client_delegate_->OnDaemonReady(client_socket.get());
+ // Restore the previous signal action for SIGCHLD.
+ if (sigaction(SIGCHLD, &old_action, NULL) < 0) {
+ PError("sigaction");
+ failed = true;
+ }
+ return !failed;
}
bool Daemon::Kill() {
« 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