• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2022 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 "host/commands/run_cvd/launch/launch.h"
17 
18 #include <string>
19 #include <unordered_set>
20 #include <utility>
21 #include <vector>
22 
23 #include <fruit/fruit.h>
24 
25 #include "common/libs/fs/shared_fd.h"
26 #include "common/libs/utils/files.h"
27 #include "common/libs/utils/result.h"
28 #include "host/libs/config/command_source.h"
29 #include "host/libs/config/known_paths.h"
30 
31 namespace cuttlefish {
32 namespace {
33 
34 // NetsimServer launches netsim server with fifos for radio HALs.
35 //
36 // netsimd -s '{devices:[
37 //  {"name":"0.0.0.0:5000", "chips":[
38 //    {"kind":"BLUETOOTH", "fdIn":10, "fdOut":11}]},
39 //  {"name":"0.0.0.0:5010", "chips":[
40 //    {"kind":"BLUETOOTH", "fdIn":14, "fdOut":15}]}]}
41 
42 // Chip and Device classes pass SharedFD fifos between ResultSetup and Commands
43 // and format the netsim json command line.
44 
45 class Chip {
46  public:
47   SharedFD fd_in;
48   SharedFD fd_out;
49 
Chip(std::string kind)50   Chip(std::string kind) : kind_(kind) {}
51 
52   // Append the chip information as Json to the command.
Append(Command & c) const53   void Append(Command& c) const {
54     c.AppendToLastParameter(R"({"kind":")", kind_, R"(","fdIn":)", fd_in,
55                             R"(,"fdOut":)", fd_out, "}");
56   }
57 
58  private:
59   std::string kind_;
60 };
61 
62 class Device {
63  public:
Device(std::string name)64   Device(std::string name) : name_(name) {}
65 
Append(Command & c) const66   void Append(Command& c) const {
67     c.AppendToLastParameter(R"({"name":")", name_, R"(","chips":[)");
68     for (int i = 0; i < chips.size(); ++i) {
69       chips[i].Append(c);
70       if (chips.size() - i > 1) {
71         c.AppendToLastParameter(",");
72       }
73     }
74     c.AppendToLastParameter("]}");
75   }
76 
77   std::vector<Chip> chips;
78 
79  private:
80   std::string name_;
81 };
82 
83 class NetsimServer : public CommandSource {
84  public:
INJECT(NetsimServer (const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance))85   INJECT(NetsimServer(const CuttlefishConfig& config,
86                       const CuttlefishConfig::InstanceSpecific& instance))
87       : config_(config), instance_(instance) {}
88 
89   // CommandSource
Commands()90   Result<std::vector<MonitorCommand>> Commands() override {
91     Command cmd(NetsimdBinary());
92     cmd.AddParameter("-s");
93     AddDevicesParameter(cmd);
94     // Release SharedFDs, they've been duped by Command
95     devices_.clear();
96     // Bluetooth controller properties file
97     cmd.AddParameter("--rootcanal_controller_properties_file=",
98                      config_.rootcanal_config_file());
99     // Default commands file
100     cmd.AddParameter("--rootcanal_default_commands_file=",
101                      config_.rootcanal_default_commands_file());
102     std::vector<MonitorCommand> commands;
103     commands.emplace_back(std::move(cmd));
104     return commands;
105   }
106 
107   // Convert devices_ to json for netsimd -s <arg>. The devices_, created and
108   // validated during ResultSetup, contains all the SharedFDs and meta-data.
109 
AddDevicesParameter(Command & c)110   void AddDevicesParameter(Command& c) {
111     c.AddParameter(R"({"devices":[)");
112     for (int i = 0; i < devices_.size(); ++i) {
113       devices_[i].Append(c);
114       if (devices_.size() - i > 1) {
115         c.AppendToLastParameter(",");
116       }
117     }
118     c.AppendToLastParameter("]}");
119   }
120 
121   // SetupFeature
Name() const122   std::string Name() const override { return "Netsim"; }
Enabled() const123   bool Enabled() const override { return instance_.start_netsim(); }
124 
125  private:
Dependencies() const126   std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
127 
ResultSetup()128   Result<void> ResultSetup() {
129     auto netsimd = HostBinaryPath("netsimd");
130     CF_EXPECT(FileExists(netsimd),
131               "Failed to find netsimd binary: " << netsimd);
132 
133     for (const auto& instance : config_.Instances()) {
134       Device device(instance.adb_ip_and_port());
135       // Add bluetooth chip if enabled
136       if (config_.netsim_radio_enabled(
137               CuttlefishConfig::NetsimRadio::Bluetooth)) {
138         Chip chip("BLUETOOTH");
139         CF_EXPECT(MakeFifo(instance, "bt_fifo_vm.in", chip.fd_in));
140         CF_EXPECT(MakeFifo(instance, "bt_fifo_vm.out", chip.fd_out));
141         device.chips.emplace_back(chip);
142       }
143       // Add other chips if enabled
144       devices_.emplace_back(device);
145     }
146     return {};
147   }
148 
MakeFifo(const CuttlefishConfig::InstanceSpecific & instance,const char * relative_path,SharedFD & fd)149   Result<void> MakeFifo(const CuttlefishConfig::InstanceSpecific& instance,
150                         const char* relative_path, SharedFD& fd) {
151     auto path = instance.PerInstanceInternalPath(relative_path);
152     unlink(path.c_str());
153     CF_EXPECT(mkfifo(path.c_str(), 0660) == 0,
154               "Failed to create fifo for Netsim: " << strerror(errno));
155 
156     fd = SharedFD::Open(path, O_RDWR);
157 
158     CF_EXPECT(fd->IsOpen(),
159               "Failed to open fifo for Netsim: " << fd->StrError());
160 
161     return {};
162   }
163 
164  private:
165   std::vector<Device> devices_;
166   const CuttlefishConfig& config_;
167   const CuttlefishConfig::InstanceSpecific& instance_;
168 };
169 
170 }  // namespace
171 
172 fruit::Component<fruit::Required<const CuttlefishConfig,
173                                  const CuttlefishConfig::InstanceSpecific>>
NetsimServerComponent()174 NetsimServerComponent() {
175   return fruit::createComponent()
176       .addMultibinding<CommandSource, NetsimServer>()
177       .addMultibinding<SetupFeature, NetsimServer>();
178 }
179 
180 }  // namespace cuttlefish
181