1 //
2 // Copyright (C) 2019 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 #include "host/commands/run_cvd/launch/wmediumd_server.h"
18 
19 #include <string>
20 #include <unordered_set>
21 #include <utility>
22 #include <vector>
23 
24 #include <android-base/logging.h>
25 #include <fruit/fruit.h>
26 
27 #include "common/libs/utils/files.h"
28 #include "common/libs/utils/network.h"
29 #include "common/libs/utils/result.h"
30 #include "host/libs/config/command_source.h"
31 #include "host/libs/config/known_paths.h"
32 #include "host/libs/config/openwrt_args.h"
33 #include "host/libs/vm_manager/crosvm_builder.h"
34 #include "host/libs/vm_manager/crosvm_manager.h"
35 
36 namespace cuttlefish {
37 namespace {
38 
39 using APBootFlow = CuttlefishConfig::InstanceSpecific::APBootFlow;
40 
41 // TODO(b/288987294) Remove dependency to InstanceSpecific config when moving
42 // to run_env is completed.
43 class OpenWrt : public CommandSource {
44  public:
INJECT(OpenWrt (const CuttlefishConfig & config,const CuttlefishConfig::EnvironmentSpecific & environment,const CuttlefishConfig::InstanceSpecific & instance,LogTeeCreator & log_tee,WmediumdServer & wmediumd_server))45   INJECT(OpenWrt(const CuttlefishConfig& config,
46                  const CuttlefishConfig::EnvironmentSpecific& environment,
47                  const CuttlefishConfig::InstanceSpecific& instance,
48                  LogTeeCreator& log_tee, WmediumdServer& wmediumd_server))
49       : config_(config),
50         environment_(environment),
51         instance_(instance),
52         log_tee_(log_tee),
53         wmediumd_server_(wmediumd_server) {}
54 
55   // CommandSource
Commands()56   Result<std::vector<MonitorCommand>> Commands() override {
57     constexpr auto crosvm_for_ap_socket = "ap_control.sock";
58 
59     CrosvmBuilder ap_cmd;
60 
61     ap_cmd.Cmd().AddPrerequisite([this]() -> Result<void> {
62       return wmediumd_server_.WaitForAvailability();
63     });
64 
65     /* TODO(b/305102099): Due to hostapd issue of OpenWRT 22.03.X versions,
66      * OpenWRT instance should be rebooted.
67      */
68     LOG(DEBUG) << "Restart OpenWRT due to hostapd issue";
69     ap_cmd.ApplyProcessRestarter(instance_.crosvm_binary(),
70                                  /*first_time_argument=*/"",
71                                  kOpenwrtVmResetExitCode);
72     ap_cmd.Cmd().AddParameter("run");
73     ap_cmd.AddControlSocket(
74         instance_.PerInstanceInternalUdsPath(crosvm_for_ap_socket),
75         instance_.crosvm_binary());
76 
77     ap_cmd.Cmd().AddParameter("--no-usb");
78     ap_cmd.Cmd().AddParameter("--core-scheduling=false");
79 
80     if (!environment_.vhost_user_mac80211_hwsim().empty()) {
81       ap_cmd.Cmd().AddParameter("--vhost-user=mac80211-hwsim,socket=",
82                                 environment_.vhost_user_mac80211_hwsim());
83     }
84     SharedFD wifi_tap;
85     if (environment_.enable_wifi()) {
86       wifi_tap = ap_cmd.AddTap(instance_.wifi_tap_name());
87     }
88 
89     // TODO(khei): Enable restore once open_wrt instance restoring is fixed
90     // if (IsRestoring(config_)) {
91     //  const std::string snapshot_dir = config_.snapshot_path();
92     //  CF_EXPECT(ap_cmd.SetToRestoreFromSnapshot(snapshot_dir, instance_.id(),
93     //                                            "_openwrt"));
94     //}
95 
96     /* TODO(kwstephenkim): delete this code when Minidroid completely disables
97      * the AP VM itself
98      */
99     if (!instance_.crosvm_use_balloon()) {
100       ap_cmd.Cmd().AddParameter("--no-balloon");
101     }
102 
103     /* TODO(kwstephenkim): delete this code when Minidroid completely disables
104      * the AP VM itself
105      */
106     if (!instance_.crosvm_use_rng()) {
107       ap_cmd.Cmd().AddParameter("--no-rng");
108     }
109 
110     if (instance_.enable_sandbox()) {
111       ap_cmd.Cmd().AddParameter("--seccomp-policy-dir=",
112                                 instance_.seccomp_policy_dir());
113     } else {
114       ap_cmd.Cmd().AddParameter("--disable-sandbox");
115     }
116     ap_cmd.AddReadWriteDisk(instance_.PerInstancePath("ap_overlay.img"));
117 
118     auto boot_logs_path =
119         instance_.PerInstanceLogPath("crosvm_openwrt_boot.log");
120     auto logs_path = instance_.PerInstanceLogPath("crosvm_openwrt.log");
121     ap_cmd.AddSerialConsoleReadOnly(boot_logs_path);
122     ap_cmd.AddHvcReadOnly(logs_path);
123 
124     auto openwrt_args = OpenwrtArgsFromConfig(instance_);
125     switch (instance_.ap_boot_flow()) {
126       case APBootFlow::Grub:
127         if (config_.vm_manager() == VmmMode::kQemu) {
128           ap_cmd.AddReadWriteDisk(
129               instance_.persistent_ap_composite_overlay_path());
130         } else {
131           ap_cmd.AddReadWriteDisk(
132               instance_.persistent_ap_composite_disk_path());
133         }
134         ap_cmd.Cmd().AddParameter("--bios=", instance_.bootloader());
135         break;
136       case APBootFlow::LegacyDirect:
137         ap_cmd.Cmd().AddParameter("--params=\"root=/dev/vda1\"");
138         for (auto& openwrt_arg : openwrt_args) {
139           ap_cmd.Cmd().AddParameter("--params=" + openwrt_arg.first + "=" +
140                                     openwrt_arg.second);
141         }
142         ap_cmd.Cmd().AddParameter(config_.ap_kernel_image());
143         break;
144       default:
145         // must not be happened
146         break;
147     }
148 
149     std::vector<MonitorCommand> commands;
150     commands.emplace_back(
151         CF_EXPECT(log_tee_.CreateLogTee(ap_cmd.Cmd(), "openwrt")));
152     commands.emplace_back(std::move(ap_cmd.Cmd()));
153     return commands;
154   }
155 
156   // SetupFeature
Name() const157   std::string Name() const override { return "OpenWrt"; }
Enabled() const158   bool Enabled() const override {
159     return instance_.ap_boot_flow() != APBootFlow::None &&
160            config_.vm_manager() == VmmMode::kCrosvm;
161   }
162 
163  private:
Dependencies() const164   std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()165   Result<void> ResultSetup() override { return {}; }
166 
167   const CuttlefishConfig& config_;
168   const CuttlefishConfig::EnvironmentSpecific& environment_;
169   const CuttlefishConfig::InstanceSpecific& instance_;
170   LogTeeCreator& log_tee_;
171   WmediumdServer& wmediumd_server_;
172 
173   static constexpr int kOpenwrtVmResetExitCode = 32;
174 };
175 
176 }  // namespace
177 
178 fruit::Component<fruit::Required<
179     const CuttlefishConfig, const CuttlefishConfig::EnvironmentSpecific,
180     const CuttlefishConfig::InstanceSpecific, LogTeeCreator, WmediumdServer>>
OpenWrtComponent()181 OpenWrtComponent() {
182   return fruit::createComponent()
183       .addMultibinding<CommandSource, OpenWrt>()
184       .addMultibinding<SetupFeature, OpenWrt>();
185 }
186 
187 }  // namespace cuttlefish
188