1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include <signal.h>
17 #include <sys/signalfd.h>
18
19 #include <android-base/logging.h>
20 #include <android-base/strings.h>
21 #include <gflags/gflags.h>
22
23 #include "common/libs/fs/shared_fd.h"
24 #include "common/libs/utils/tee_logging.h"
25 #include "host/libs/config/cuttlefish_config.h"
26
27 DEFINE_string(process_name, "", "The process to credit log messages to");
28 DEFINE_int32(log_fd_in, -1, "The file descriptor to read logs from.");
29
main(int argc,char ** argv)30 int main(int argc, char** argv) {
31 ::android::base::InitLogging(argv, android::base::StderrLogger);
32 google::ParseCommandLineFlags(&argc, &argv, /* remove_flags */ true);
33
34 CHECK(FLAGS_log_fd_in >= 0) << "-log_fd_in is required";
35
36 auto config = cuttlefish::CuttlefishConfig::Get();
37
38 CHECK(config) << "Could not open cuttlefish config";
39
40 auto instance = config->ForDefaultInstance();
41
42 if (instance.run_as_daemon()) {
43 android::base::SetLogger(
44 cuttlefish::LogToFiles({instance.launcher_log_path()}));
45 } else {
46 android::base::SetLogger(
47 cuttlefish::LogToStderrAndFiles({instance.launcher_log_path()}));
48 }
49
50 auto log_fd = cuttlefish::SharedFD::Dup(FLAGS_log_fd_in);
51 CHECK(log_fd->IsOpen()) << "Failed to dup log_fd_in: " << log_fd->StrError();
52 close(FLAGS_log_fd_in);
53
54 if (FLAGS_process_name.size() > 0) {
55 android::base::SetDefaultTag(FLAGS_process_name);
56 }
57
58 // mask SIGINT and handle it using signalfd
59 sigset_t mask;
60 sigemptyset(&mask);
61 sigaddset(&mask, SIGINT);
62 CHECK(sigprocmask(SIG_BLOCK, &mask, NULL) == 0)
63 << "sigprocmask failed: " << strerror(errno);
64 int sfd = signalfd(-1, &mask, 0);
65 CHECK(sfd >= 0) << "signalfd failed: " << strerror(errno);
66 auto int_fd = cuttlefish::SharedFD::Dup(sfd);
67 close(sfd);
68
69 auto poll_fds = std::vector<cuttlefish::PollSharedFd>{
70 cuttlefish::PollSharedFd{
71 .fd = log_fd,
72 .events = POLL_IN,
73 .revents = 0,
74 },
75 cuttlefish::PollSharedFd{
76 .fd = int_fd,
77 .events = POLL_IN,
78 .revents = 0,
79 },
80 };
81
82 LOG(DEBUG) << "Starting to read from process " << FLAGS_process_name;
83
84 char buf[1 << 16];
85 ssize_t chars_read = 0;
86 for (;;) {
87 // We can assume all writers to `log_fd` have completed before a SIGINT is
88 // sent, but we need to make sure we've actually read all the data before
89 // exiting. So, keep reading from `log_fd` until both (1) we get SIGINT and
90 // (2) `log_fd` is empty (but not necessarily EOF).
91 //
92 // This could be simpler if all the writers would close their FDs when they
93 // are finished. Then, we could just read until EOF. However that would
94 // require more work elsewhere in cuttlefish.
95 CHECK(cuttlefish::SharedFD::Poll(poll_fds, /*timeout=*/-1) >= 0)
96 << "poll failed: " << strerror(errno);
97 if (poll_fds[0].revents) {
98 chars_read = log_fd->Read(buf, sizeof(buf));
99 if (chars_read < 0) {
100 LOG(DEBUG) << "Failed to read from process " << FLAGS_process_name
101 << ": " << log_fd->StrError();
102 break;
103 }
104 if (chars_read == 0) {
105 break;
106 }
107 auto trimmed = android::base::Trim(std::string_view(buf, chars_read));
108 // Newlines inside `trimmed` are handled by the android logging code.
109 // These checks attempt to determine the log severity coming from crosvm.
110 // There is no guarantee of success all the time since log line boundaries
111 // could be out sync with the reads, but that's ok.
112 //
113 // TODO(b/270424669): These checks are wrong, the format is
114 // "[<timestamp> ERROR". Maybe just stop bothering and send
115 // everything to LOG(DEBUG).
116 if (android::base::StartsWith(trimmed, "[INFO")) {
117 LOG(DEBUG) << trimmed;
118 } else if (android::base::StartsWith(trimmed, "[ERROR")) {
119 LOG(ERROR) << trimmed;
120 } else if (android::base::StartsWith(trimmed, "[WARNING")) {
121 LOG(WARNING) << trimmed;
122 } else if (android::base::StartsWith(trimmed, "[VERBOSE")) {
123 LOG(VERBOSE) << trimmed;
124 } else {
125 LOG(DEBUG) << trimmed;
126 }
127
128 // Go back to polling immediately to see if there is more data, don't
129 // handle any signals yet.
130 continue;
131 }
132 if (poll_fds[1].revents) {
133 struct signalfd_siginfo siginfo;
134 int s = int_fd->Read(&siginfo, sizeof(siginfo));
135 CHECK(s == sizeof(siginfo)) << "bad read size on signalfd, expected "
136 << sizeof(siginfo) << " got " << s;
137 CHECK(siginfo.ssi_signo == SIGINT)
138 << "unexpected signal: " << siginfo.ssi_signo;
139 break;
140 }
141 }
142
143 LOG(DEBUG) << "Finished reading from process " << FLAGS_process_name;
144 }
145