1 /*
2 * Copyright (C) 2017 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
17 #include "host/commands/kernel_log_monitor/kernel_log_server.h"
18
19 #include <map>
20 #include <utility>
21
22 #include <android-base/logging.h>
23 #include <android-base/strings.h>
24 #include <netinet/in.h>
25 #include "common/libs/fs/shared_select.h"
26 #include "host/libs/config/cuttlefish_config.h"
27
28 using cuttlefish::SharedFD;
29
30 namespace {
31 static const std::map<std::string, std::string> kInformationalPatterns = {
32 {"U-Boot ", "GUEST_UBOOT_VERSION: "},
33 {"] Linux version ", "GUEST_KERNEL_VERSION: "},
34 {"GUEST_BUILD_FINGERPRINT: ", "GUEST_BUILD_FINGERPRINT: "},
35 };
36
37 static const std::map<std::string, monitor::Event> kStageToEventMap = {
38 {cuttlefish::kBootStartedMessage, monitor::Event::BootStarted},
39 {cuttlefish::kBootCompletedMessage, monitor::Event::BootCompleted},
40 {cuttlefish::kBootFailedMessage, monitor::Event::BootFailed},
41 {cuttlefish::kMobileNetworkConnectedMessage,
42 monitor::Event::MobileNetworkConnected},
43 {cuttlefish::kWifiConnectedMessage, monitor::Event::WifiNetworkConnected},
44 {cuttlefish::kEthernetConnectedMessage, monitor::Event::EthernetNetworkConnected},
45 // TODO(b/131864854): Replace this with a string less likely to change
46 {"init: starting service 'adbd'...", monitor::Event::AdbdStarted},
47 {cuttlefish::kScreenChangedMessage, monitor::Event::ScreenChanged},
48 };
49
ProcessSubscriptions(Json::Value message,std::vector<monitor::EventCallback> * subscribers)50 void ProcessSubscriptions(
51 Json::Value message,
52 std::vector<monitor::EventCallback>* subscribers) {
53 auto active_subscription_count = subscribers->size();
54 std::size_t idx = 0;
55 while (idx < active_subscription_count) {
56 // Call the callback
57 auto action = (*subscribers)[idx](message);
58 if (action == monitor::SubscriptionAction::ContinueSubscription) {
59 ++idx;
60 } else {
61 // Cancel the subscription by swaping it with the last active subscription
62 // and decreasing the active subscription count
63 --active_subscription_count;
64 std::swap((*subscribers)[idx], (*subscribers)[active_subscription_count]);
65 }
66 }
67 // Keep only the active subscriptions
68 subscribers->resize(active_subscription_count);
69 }
70 } // namespace
71
72 namespace monitor {
KernelLogServer(cuttlefish::SharedFD pipe_fd,const std::string & log_name,bool deprecated_boot_completed)73 KernelLogServer::KernelLogServer(cuttlefish::SharedFD pipe_fd,
74 const std::string& log_name,
75 bool deprecated_boot_completed)
76 : pipe_fd_(pipe_fd),
77 log_fd_(cuttlefish::SharedFD::Open(log_name.c_str(), O_CREAT | O_RDWR | O_APPEND, 0666)),
78 deprecated_boot_completed_(deprecated_boot_completed) {}
79
BeforeSelect(cuttlefish::SharedFDSet * fd_read) const80 void KernelLogServer::BeforeSelect(cuttlefish::SharedFDSet* fd_read) const {
81 fd_read->Set(pipe_fd_);
82 }
83
AfterSelect(const cuttlefish::SharedFDSet & fd_read)84 void KernelLogServer::AfterSelect(const cuttlefish::SharedFDSet& fd_read) {
85 if (fd_read.IsSet(pipe_fd_)) {
86 HandleIncomingMessage();
87 }
88 }
89
SubscribeToEvents(monitor::EventCallback callback)90 void KernelLogServer::SubscribeToEvents(monitor::EventCallback callback) {
91 subscribers_.push_back(callback);
92 }
93
HandleIncomingMessage()94 bool KernelLogServer::HandleIncomingMessage() {
95 const size_t buf_len = 256;
96 char buf[buf_len];
97 ssize_t ret = pipe_fd_->Read(buf, buf_len);
98 if (ret < 0) {
99 LOG(ERROR) << "Could not read kernel logs: " << pipe_fd_->StrError();
100 return false;
101 }
102 if (ret == 0) return false;
103 // Write the log to a file
104 if (log_fd_->Write(buf, ret) < 0) {
105 LOG(ERROR) << "Could not write kernel log to file: " << log_fd_->StrError();
106 return false;
107 }
108
109 // Detect VIRTUAL_DEVICE_BOOT_*
110 for (ssize_t i=0; i<ret; i++) {
111 if ('\n' == buf[i]) {
112 for (auto& info_kv : kInformationalPatterns) {
113 auto& match = info_kv.first;
114 auto& prefix = info_kv.second;
115 auto pos = line_.find(match);
116 if (std::string::npos != pos) {
117 LOG(INFO) << prefix << line_.substr(pos + match.size());
118 }
119 }
120 for (auto& stage_kv : kStageToEventMap) {
121 auto& stage = stage_kv.first;
122 auto event = stage_kv.second;
123 auto pos = line_.find(stage);
124 if (std::string::npos != pos) {
125 // Log the stage
126 LOG(INFO) << stage;
127
128 Json::Value message;
129 message["event"] = event;
130 Json::Value metadata;
131 // Expect space-separated key=value pairs in the log message.
132 const auto& fields = android::base::Split(
133 line_.substr(pos + stage.size()), " ");
134 for (std::string field : fields) {
135 field = android::base::Trim(field);
136 if (field.empty()) {
137 // Expected; android::base::Split() always returns at least
138 // one (possibly empty) string.
139 LOG(DEBUG) << "Empty field for line: " << line_;
140 continue;
141 }
142 const auto& keyvalue = android::base::Split(field, "=");
143 if (keyvalue.size() != 2) {
144 LOG(WARNING) << "Field is not in key=value format: " << field;
145 continue;
146 }
147 metadata[keyvalue[0]] = keyvalue[1];
148 }
149 message["metadata"] = metadata;
150 ProcessSubscriptions(message, &subscribers_);
151
152 //TODO(b/69417553) Remove this when our clients have transitioned to the
153 // new boot completed
154 if (deprecated_boot_completed_) {
155 // Write to host kernel log
156 FILE* log = popen("/usr/bin/sudo /usr/bin/tee /dev/kmsg", "w");
157 fprintf(log, "%s\n", stage.c_str());
158 fclose(log);
159 }
160 }
161 }
162 line_.clear();
163 }
164 line_.append(1, buf[i]);
165 }
166
167 return true;
168 }
169
170 } // namespace monitor
171