1 //
2 // Copyright (C) 2023 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 <unordered_set>
17 #include <vector>
18 
19 #include <android-base/logging.h>
20 #include <fruit/fruit.h>
21 #include <json/json.h>
22 
23 #include "common/libs/utils/files.h"
24 #include "common/libs/utils/result.h"
25 #include "host/commands/run_cvd/launch/launch.h"
26 #include "host/commands/run_cvd/launch/log_tee_creator.h"
27 #include "host/libs/config/command_source.h"
28 #include "host/libs/config/cuttlefish_config.h"
29 #include "host/libs/config/known_paths.h"
30 
31 
32 // timeout for the MCU channels to be created after the start command is issued
33 #define MCU_START_TIMEOUT 30
34 
35 namespace cuttlefish {
36 namespace {
37 
38 class Mcu : public vm_manager::VmmDependencyCommand {
39  public:
INJECT(Mcu (const CuttlefishConfig::InstanceSpecific & instance,LogTeeCreator & log_tee))40   INJECT(Mcu(const CuttlefishConfig::InstanceSpecific& instance,
41              LogTeeCreator& log_tee))
42       :instance_(instance), log_tee_(log_tee) {}
43 
ResultSetup()44   Result<void> ResultSetup() override {
45     if (!Enabled()) {
46       return {};
47     }
48 
49     mcu_dir_ = instance_.PerInstanceInternalPath("/mcu/");
50     CF_EXPECT(EnsureDirectoryExists(mcu_dir_),
51               "MCU directory cannot be created.");
52     return {};
53   }
54 
55   // CommandSource
Commands()56   Result<std::vector<MonitorCommand>> Commands() override {
57     if (!Enabled()) {
58       return {};
59     }
60 
61     auto start = instance_.mcu()["start-cmd"];
62     CF_EXPECT(start.type() == Json::arrayValue,
63               "mcu: config: start-cmd: array expected");
64     CF_EXPECT(start.size() > 0, "mcu: config: empty start-cmd");
65     Command command(android::base::StringReplace(start[0].asString(), "${bin}",
66                                                  HostBinaryPath(""), true));
67 
68     for (unsigned int i = 1; i < start.size(); i++) {
69       auto param = start[i].asString();
70       param = android::base::StringReplace(param, "${wdir}", mcu_dir_, true);
71       param = android::base::StringReplace(param, "${bin}", HostBinaryPath(""),
72                                            true);
73       command.AddParameter(param);
74     }
75 
76     std::vector<MonitorCommand> commands;
77     commands.emplace_back(CF_EXPECT(log_tee_.CreateLogTee(command, "mcu")));
78     commands.emplace_back(std::move(command));
79     return commands;
80   }
81 
82   // SetupFeature
Name() const83   std::string Name() const override { return "MCU"; }
Enabled() const84   bool Enabled() const override {
85     return instance_.mcu().type() != Json::nullValue;
86   }
87 
88   // StatusCheckCommandSource
WaitForAvailability() const89   Result<void> WaitForAvailability() const {
90     if (!Enabled()) {
91       return {};
92     }
93 
94     auto control = instance_.mcu()["control"]["path"];
95     if (control.type() == Json::stringValue) {
96       CF_EXPECT(WaitForFile(mcu_dir_ + "/" + control.asString(),
97                             MCU_START_TIMEOUT));
98     }
99     auto uart0 = instance_.mcu()["uart0"]["path"];
100     if (uart0.type() == Json::stringValue) {
101       CF_EXPECT(WaitForFile(mcu_dir_ + "/" + uart0.asString(),
102                             MCU_START_TIMEOUT));
103     }
104     return {};
105   }
106 
107  private:
Dependencies() const108   std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
109 
110   std::string mcu_dir_;
111   const CuttlefishConfig::InstanceSpecific& instance_;
112   LogTeeCreator& log_tee_;
113 };
114 
115 }  // namespace
116 
117 fruit::Component<
118     fruit::Required<const CuttlefishConfig,
119                     const CuttlefishConfig::InstanceSpecific, LogTeeCreator>>
McuComponent()120 McuComponent() {
121   return fruit::createComponent()
122       .addMultibinding<vm_manager::VmmDependencyCommand, Mcu>()
123       .addMultibinding<CommandSource, Mcu>()
124       .addMultibinding<SetupFeature, Mcu>();
125 }
126 
127 }  // namespace cuttlefish
128