Home | History | Annotate | Download | only in stop_cvd
      1 /*
      2  * Copyright (C) 2018 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 <inttypes.h>
     18 #include <limits.h>
     19 #include <stdio.h>
     20 #include <stdint.h>
     21 #include <stdlib.h>
     22 #include <sys/types.h>
     23 #include <sys/stat.h>
     24 #include <sys/wait.h>
     25 #include <fcntl.h>
     26 #include <unistd.h>
     27 #include <signal.h>
     28 
     29 #include <algorithm>
     30 #include <cstdlib>
     31 #include <fstream>
     32 #include <iomanip>
     33 #include <memory>
     34 #include <sstream>
     35 #include <string>
     36 #include <vector>
     37 
     38 #include <gflags/gflags.h>
     39 #include <glog/logging.h>
     40 
     41 #include "common/libs/fs/shared_fd.h"
     42 #include "common/libs/fs/shared_select.h"
     43 #include "common/libs/utils/environment.h"
     44 #include "host/commands/launch/launcher_defs.h"
     45 #include "host/libs/config/cuttlefish_config.h"
     46 #include "host/libs/vm_manager/vm_manager.h"
     47 
     48 DEFINE_int32(wait_for_launcher, 5,
     49              "How many seconds to wait for the launcher to respond to the stop "
     50              "command. A value of zero means wait indefinetly");
     51 
     52 namespace {
     53 // Gets a set of the possible process groups of a previous launch
     54 std::set<pid_t> GetCandidateProcessGroups() {
     55   std::string cmd = "fuser";
     56   // Add the instance directory
     57   cmd += " " + cvd::StringFromEnv("HOME", ".") + "/cuttlefish_runtime/*";
     58   // Add the shared memory file
     59   cmd += " " + vsoc::GetPerInstanceDefault("/dev/shm/cvd-");
     60   std::shared_ptr<FILE> cmd_out(popen(cmd.c_str(), "r"), pclose);
     61   if (!cmd_out) {
     62     LOG(ERROR) << "Unable to execute '" << cmd << "': " << strerror(errno);
     63     return {};
     64   }
     65   int64_t pid;
     66   std::set<pid_t> ret{};
     67   while(fscanf(cmd_out.get(), "%" PRId64, &pid) != EOF) {
     68     pid_t pgid = getpgid(static_cast<pid_t>(pid));
     69     if (pgid < 0) {
     70       LOG(ERROR) << "Unable to get process group of " << pid << ": "
     71                  << strerror(errno);
     72       continue;
     73     }
     74     ret.insert(pgid);
     75   }
     76   // The process group of stop_cvd should not be killed
     77   ret.erase(getpgrp());
     78   return ret;
     79 }
     80 
     81 int FallBackStop() {
     82   auto exit_code = 1; // Having to fallback is an error
     83 
     84   auto process_groups = GetCandidateProcessGroups();
     85   for (auto pgid: process_groups) {
     86     LOG(INFO) << "Sending SIGKILL to process group " << pgid;
     87     auto retval = killpg(pgid, SIGKILL);
     88     if (retval < 0) {
     89       LOG(ERROR) << "Failed to kill process group " << pgid << ": "
     90                  << strerror(errno);
     91       exit_code |= 4;
     92     }
     93   }
     94 
     95   return exit_code;
     96 }
     97 }  // anonymous namespace
     98 
     99 int main(int argc, char** argv) {
    100   ::android::base::InitLogging(argv, android::base::StderrLogger);
    101   google::ParseCommandLineFlags(&argc, &argv, true);
    102 
    103   auto config = vsoc::CuttlefishConfig::Get();
    104   if (!config) {
    105     LOG(ERROR) << "Failed to obtain config object";
    106     return FallBackStop();
    107   }
    108 
    109   auto monitor_path = config->launcher_monitor_socket_path();
    110   if (monitor_path.empty()) {
    111     LOG(ERROR) << "No path to launcher monitor found";
    112     return FallBackStop();
    113   }
    114   auto monitor_socket = cvd::SharedFD::SocketLocalClient(monitor_path.c_str(),
    115                                                          false, SOCK_STREAM);
    116   if (!monitor_socket->IsOpen()) {
    117     LOG(ERROR) << "Unable to connect to launcher monitor at " << monitor_path
    118                << ": " << monitor_socket->StrError();
    119     return FallBackStop();
    120   }
    121   auto request = cvd::LauncherAction::kStop;
    122   auto bytes_sent = monitor_socket->Send(&request, sizeof(request), 0);
    123   if (bytes_sent < 0) {
    124     LOG(ERROR) << "Error sending launcher monitor the stop command: "
    125                << monitor_socket->StrError();
    126     return FallBackStop();
    127   }
    128   // Perform a select with a timeout to guard against launcher hanging
    129   cvd::SharedFDSet read_set;
    130   read_set.Set(monitor_socket);
    131   struct timeval timeout = {FLAGS_wait_for_launcher, 0};
    132   int selected = cvd::Select(&read_set, nullptr, nullptr,
    133                              FLAGS_wait_for_launcher <= 0 ? nullptr : &timeout);
    134   if (selected < 0){
    135     LOG(ERROR) << "Failed communication with the launcher monitor: "
    136                << strerror(errno);
    137     return FallBackStop();
    138   }
    139   if (selected == 0) {
    140     LOG(ERROR) << "Timeout expired waiting for launcher monitor to respond";
    141     return FallBackStop();
    142   }
    143   cvd::LauncherResponse response;
    144   auto bytes_recv = monitor_socket->Recv(&response, sizeof(response), 0);
    145   if (bytes_recv < 0) {
    146     LOG(ERROR) << "Error receiving response from launcher monitor: "
    147                << monitor_socket->StrError();
    148     return FallBackStop();
    149   }
    150   if (response != cvd::LauncherResponse::kSuccess) {
    151     LOG(ERROR) << "Received '" << static_cast<char>(response)
    152                << "' response from launcher monitor";
    153     return FallBackStop();
    154   }
    155   LOG(INFO) << "Successfully stopped device";
    156   return 0;
    157 }
    158