• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #pragma once
17 
18 #include <optional>
19 #include <string>
20 #include <tuple>
21 #include <type_traits>
22 #include <utility>
23 #include <vector>
24 
25 #include <android-base/logging.h>
26 #include <fruit/fruit.h>
27 
28 #include "common/libs/utils/result.h"
29 #include "common/libs/utils/type_name.h"
30 #include "host/libs/config/command_source.h"
31 #include "host/libs/config/feature.h"
32 #include "host/libs/config/kernel_log_pipe_provider.h"
33 
34 namespace cuttlefish {
35 
36 template <class...>
37 constexpr std::false_type CommandAlwaysFalse{};
38 
39 template <auto Fn, typename R, typename... Args>
40 class GenericCommandSource : public CommandSource,
41                              public KernelLogPipeConsumer {
42  public:
INJECT(GenericCommandSource (Args...args))43   INJECT(GenericCommandSource(Args... args))
44       : args_(std::forward_as_tuple(args...)) {}
45 
ResultSetup()46   Result<void> ResultSetup() override {
47     commands_.clear();
48     if constexpr (std::is_same_v<R, Result<std::vector<MonitorCommand>>>) {
49       commands_ = CF_EXPECT(std::apply(Fn, args_));
50     } else if constexpr (std::is_same_v<R, std::vector<MonitorCommand>>) {
51       commands_ = std::apply(Fn, args_);
52     } else if constexpr (std::is_same_v<R, Result<MonitorCommand>>) {
53       commands_.emplace_back(CF_EXPECT(std::apply(Fn, args_)));
54     } else if constexpr (std::is_same_v<R, MonitorCommand>) {
55       commands_.emplace_back(std::apply(Fn, args_));
56     } else if constexpr (std::is_same_v<
57                              R, Result<std::optional<MonitorCommand>>>) {
58       auto cmd = CF_EXPECT(std::apply(Fn, args_));
59       if (cmd) {
60         commands_.emplace_back(std::move(*cmd));
61       }
62     } else if constexpr (std::is_same_v<R, std::optional<MonitorCommand>>) {
63       auto cmd = std::apply(Fn, args_);
64       if (cmd) {
65         commands_.emplace_back(std::move(*cmd));
66       }
67     } else {
68       static_assert(CommandAlwaysFalse<R>, "Unexpected AutoCmd return type");
69     }
70     return {};
71   }
72 
Name()73   std::string Name() const override {
74     static constexpr auto kName = ValueName<Fn>();
75     return std::string(kName);
76   }
77 
Dependencies()78   std::unordered_set<SetupFeature*> Dependencies() const override {
79     return SetupFeatureDeps(args_);
80   }
81 
Commands()82   Result<std::vector<MonitorCommand>> Commands() override {
83     return std::move(commands_);
84   }
85 
86  private:
87   std::tuple<Args...> args_;
88   std::vector<MonitorCommand> commands_;
89 };
90 
91 template <auto Fn1, typename Fn2>
92 struct GenericCommandImpl;
93 
94 template <auto Fn, typename R, typename... Args>
95 struct GenericCommandImpl<Fn, R (*)(Args...)> {
96   using Type = GenericCommandSource<Fn, R, Args...>;
97 
98   static fruit::Component<
99       fruit::Required<typename std::remove_reference_t<Args>...>, Type>
100   Component() {
101     auto cmd = fruit::createComponent()
102                    .template addMultibinding<CommandSource, Type>()
103                    .template addMultibinding<SetupFeature, Type>();
104     constexpr bool uses_kernel_log_pipe =
105         (std::is_base_of_v<KernelLogPipeProvider,
106                            std::remove_reference_t<Args>> ||
107          ...);
108     if constexpr (uses_kernel_log_pipe) {
109       return cmd.template addMultibinding<KernelLogPipeConsumer, Type>();
110     } else {
111       return cmd;
112     }
113   }
114 };
115 
116 template <auto Fn>
117 using AutoCmd = GenericCommandImpl<Fn, decltype(Fn)>;
118 
119 }  // namespace cuttlefish
120