Home | History | Annotate | Download | only in monitor
      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/libs/monitor/kernel_log_server.h"
     18 
     19 #include <glog/logging.h>
     20 #include <netinet/in.h>
     21 #include "common/libs/fs/shared_select.h"
     22 
     23 using cvd::SharedFD;
     24 
     25 namespace {
     26 static const std::string kVirtualDeviceStages[] = {
     27   "VIRTUAL_DEVICE_BOOT_STARTED",
     28   "VIRTUAL_DEVICE_BOOT_COMPLETED",
     29   "VIRTUAL_DEVICE_BOOT_FAILED",
     30 };
     31 }  // namespace
     32 
     33 namespace monitor {
     34 KernelLogServer::KernelLogServer(const std::string& socket_name,
     35                                  const std::string& log_name,
     36                                  bool deprecated_boot_completed)
     37     : name_(socket_name),
     38       log_fd_(cvd::SharedFD::Open(
     39           log_name.c_str(), O_CREAT | O_RDWR, 0666)),
     40       deprecated_boot_completed_(deprecated_boot_completed) {}
     41 
     42 bool KernelLogServer::Init() { return CreateServerSocket(); }
     43 
     44 // Open new listening server socket.
     45 // Returns false, if listening socket could not be created.
     46 bool KernelLogServer::CreateServerSocket() {
     47   LOG(INFO) << "Starting server socket: " << name_;
     48 
     49   server_fd_ =
     50       cvd::SharedFD::SocketLocalServer(name_.c_str(), false, SOCK_STREAM, 0666);
     51   if (!server_fd_->IsOpen()) {
     52     LOG(ERROR) << "Could not create socket: " << server_fd_->StrError();
     53     return false;
     54   }
     55   return true;
     56 }
     57 
     58 void KernelLogServer::BeforeSelect(cvd::SharedFDSet* fd_read) const {
     59   if (!client_fd_->IsOpen()) fd_read->Set(server_fd_);
     60   if (client_fd_->IsOpen()) fd_read->Set(client_fd_);
     61 }
     62 
     63 void KernelLogServer::AfterSelect(const cvd::SharedFDSet& fd_read) {
     64   if (fd_read.IsSet(server_fd_)) HandleIncomingConnection();
     65 
     66   if (client_fd_->IsOpen() && fd_read.IsSet(client_fd_)) {
     67     if (!HandleIncomingMessage()) {
     68       client_fd_->Close();
     69     }
     70   }
     71 }
     72 
     73 // Accept new kernel log connection.
     74 void KernelLogServer::HandleIncomingConnection() {
     75   if (client_fd_->IsOpen()) {
     76     LOG(ERROR) << "Client already connected. No longer accepting connection.";
     77     return;
     78   }
     79 
     80   client_fd_ = SharedFD::Accept(*server_fd_, nullptr, nullptr);
     81   if (!client_fd_->IsOpen()) {
     82     LOG(ERROR) << "Client connection failed: " << client_fd_->StrError();
     83     return;
     84   }
     85   if (client_fd_->Fcntl(F_SETFL, O_NONBLOCK) == -1) {
     86     LOG(ERROR) << "Client connection refused O_NONBLOCK: " << client_fd_->StrError();
     87   }
     88 }
     89 
     90 bool KernelLogServer::HandleIncomingMessage() {
     91   const size_t buf_len = 256;
     92   char buf[buf_len];
     93   ssize_t ret = client_fd_->Read(buf, buf_len);
     94   if (ret < 0) {
     95     LOG(ERROR) << "Could not read from QEmu serial port: " << client_fd_->StrError();
     96     return false;
     97   }
     98   if (ret == 0) return false;
     99   // Write the log to a file
    100   if (log_fd_->Write(buf, ret) < 0) {
    101     LOG(ERROR) << "Could not write kernel log to file: " << log_fd_->StrError();
    102     return false;
    103   }
    104 
    105   // Detect VIRTUAL_DEVICE_BOOT_*
    106   for (ssize_t i=0; i<ret; i++) {
    107     if ('\n' == buf[i]) {
    108       for (auto stage : kVirtualDeviceStages) {
    109         if (std::string::npos != line_.find(stage)) {
    110           LOG(INFO) << stage;
    111           //TODO(b/69417553) Remove this when our clients have transitioned to the
    112           // new boot completed
    113           if (deprecated_boot_completed_) {
    114             // Write to host kernel log
    115             FILE* log = popen("/usr/bin/sudo /usr/bin/tee /dev/kmsg", "w");
    116             fprintf(log, "%s\n", stage.c_str());
    117             fclose(log);
    118           }
    119         }
    120       }
    121       line_.clear();
    122     }
    123     line_.append(1, buf[i]);
    124   }
    125 
    126   return true;
    127 }
    128 
    129 }  // namespace monitor
    130