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