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 <unistd.h>
18 
19 #include <android-base/strings.h>
20 #include <fmt/format.h>
21 #include <gflags/gflags.h>
22 
23 #include "common/libs/fs/shared_buf.h"
24 #include "common/libs/fs/shared_fd.h"
25 #include "common/libs/fs/shared_select.h"
26 #include "common/libs/utils/tee_logging.h"
27 #include "host/commands/modem_simulator/modem_simulator.h"
28 #include "host/libs/config/cuttlefish_config.h"
29 
30 // we can start multiple modems simultaneously; each modem
31 // will listen to one server fd for incoming sms/phone call
32 // there should be at least 1 valid fd
33 DEFINE_string(server_fds, "", "A comma separated list of file descriptors");
34 DEFINE_int32(sim_type, 1, "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases");
35 
36 namespace cuttlefish {
37 namespace {
38 
ServerFdsFromCmdline()39 std::vector<SharedFD> ServerFdsFromCmdline() {
40   // Validate the parameter
41   std::string fd_list = FLAGS_server_fds;
42   for (auto c: fd_list) {
43     if (c != ',' && (c < '0' || c > '9')) {
44       LOG(ERROR) << "Invalid file descriptor list: " << fd_list;
45       std::exit(1);
46     }
47   }
48 
49   auto fds = android::base::Split(fd_list, ",");
50   std::vector<SharedFD> shared_fds;
51   for (auto& fd_str: fds) {
52     auto fd = std::stoi(fd_str);
53     auto shared_fd = SharedFD::Dup(fd);
54     close(fd);
55     shared_fds.push_back(shared_fd);
56   }
57 
58   return shared_fds;
59 }
60 
ModemSimulatorMain(int argc,char ** argv)61 int ModemSimulatorMain(int argc, char** argv) {
62   ::android::base::InitLogging(argv, android::base::StderrLogger);
63   google::ParseCommandLineFlags(&argc, &argv, false);
64 
65   // Modem simulator log saved in cuttlefish_runtime
66   auto config = CuttlefishConfig::Get();
67   auto instance = config->ForDefaultInstance();
68 
69   auto modem_log_path = instance.PerInstanceLogPath("modem_simulator.log");
70 
71   {
72     auto log_path = instance.launcher_log_path();
73     std::vector<std::string> log_files{log_path, modem_log_path};
74     android::base::SetLogger(LogToStderrAndFiles(log_files));
75   }
76 
77   LOG(INFO) << "Start modem simulator, server_fds: " << FLAGS_server_fds
78             << ", Sim type: " << ((FLAGS_sim_type == 2) ?
79                 "special for CtsCarrierApiTestCases" : "normal" );
80 
81   auto server_fds = ServerFdsFromCmdline();
82   if (server_fds.empty()) {
83     LOG(ERROR) << "Need to provide server fd";
84     return -1;
85   }
86 
87   NvramConfig::InitNvramConfigService(server_fds.size(), FLAGS_sim_type);
88 
89   // Don't get a SIGPIPE from the clients
90   if (sigaction(SIGPIPE, nullptr, nullptr) != 0) {
91     LOG(ERROR) << "Failed to set SIGPIPE to be ignored: " << strerror(errno);
92   }
93 
94   auto nvram_config = NvramConfig::Get();
95   const auto nvram_config_file = nvram_config->ConfigFileLocation();
96 
97   // Start channel monitor, wait for RIL to connect
98   int32_t modem_id = 0;
99   std::vector<std::unique_ptr<ModemSimulator>> modem_simulators;
100 
101   for (auto& fd : server_fds) {
102     CHECK(fd->IsOpen()) << "Error creating or inheriting modem simulator server: "
103         << fd->StrError();
104 
105     auto modem_simulator = std::make_unique<ModemSimulator>(modem_id);
106     auto channel_monitor =
107         std::make_unique<ChannelMonitor>(*modem_simulator.get(), fd);
108 
109     modem_simulator->Initialize(std::move(channel_monitor));
110 
111     modem_simulators.emplace_back(std::move(modem_simulator));
112 
113     modem_id++;
114   }
115 
116   // Monitor exit request and
117   // remote call, remote sms from other cuttlefish instance
118   std::string monitor_socket_name =
119       fmt::format("modem_simulator{}", instance.modem_simulator_host_id());
120 
121   auto monitor_socket = SharedFD::SocketLocalServer(monitor_socket_name.c_str(),
122                                                     true, SOCK_STREAM, 0666);
123   if (!monitor_socket->IsOpen()) {
124     LOG(ERROR) << "Unable to create monitor socket for modem simulator";
125     std::exit(kServerError);
126   }
127 
128   // Server loop
129   while (true) {
130     SharedFDSet read_set;
131     read_set.Set(monitor_socket);
132     int num_fds = Select(&read_set, nullptr, nullptr, nullptr);
133     if (num_fds <= 0) {  // Ignore select error
134       LOG(ERROR) << "Select call returned error : " << strerror(errno);
135     } else if (read_set.IsSet(monitor_socket)) {
136       auto conn = SharedFD::Accept(*monitor_socket);
137       std::string buf(4, ' ');
138       auto read = ReadExact(conn, &buf);
139       if (read <= 0) {
140         conn->Close();
141         LOG(WARNING) << "Detected close from the other side";
142         continue;
143       }
144       if (buf == "STOP") {  // Exit request from parent process
145         LOG(INFO) << "Exit request from parent process";
146         nvram_config->SaveToFile(nvram_config_file);
147         for (auto& modem : modem_simulators) {
148           modem->SaveModemState();
149         }
150         WriteAll(conn, "OK");  // Ignore the return value. Exit anyway.
151         std::exit(kSuccess);
152       } else if (buf.compare(0, 3, "REM") == 0) {  // REMO for modem id 0 ...
153         // Remote request from other cuttlefish instance
154         int id = std::stoi(buf.substr(3, 1));
155         if (id >= modem_simulators.size()) {
156           LOG(ERROR) << "Not supported modem simulator count: " << id;
157         } else {
158           modem_simulators[id]->SetRemoteClient(conn, true);
159         }
160       }
161     }
162   }
163   // Until kill or exit
164 }
165 
166 }  // namespace
167 }  // namespace cuttlefish
168 
main(int argc,char ** argv)169 int main(int argc, char** argv) {
170   return cuttlefish::ModemSimulatorMain(argc, argv);
171 }
172