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 Enabled()73 bool Enabled() const override { 74 return true; // TODO(schuffelen): Delete `Enabled()`, it hasn't been useful 75 } 76 Name()77 std::string Name() const override { 78 static constexpr auto kName = ValueName<Fn>(); 79 return std::string(kName); 80 } 81 Dependencies()82 std::unordered_set<SetupFeature*> Dependencies() const override { 83 return SetupFeatureDeps(args_); 84 } 85 Commands()86 Result<std::vector<MonitorCommand>> Commands() override { 87 return std::move(commands_); 88 } 89 90 private: 91 std::tuple<Args...> args_; 92 std::vector<MonitorCommand> commands_; 93 }; 94 95 template <auto Fn1, typename Fn2> 96 struct GenericCommandImpl; 97 98 template <auto Fn, typename R, typename... Args> 99 struct GenericCommandImpl<Fn, R (*)(Args...)> { 100 using Type = GenericCommandSource<Fn, R, Args...>; 101 102 static fruit::Component< 103 fruit::Required<typename std::remove_reference_t<Args>...>, Type> 104 Component() { 105 auto cmd = fruit::createComponent() 106 .template addMultibinding<CommandSource, Type>() 107 .template addMultibinding<SetupFeature, Type>(); 108 constexpr bool uses_kernel_log_pipe = 109 (std::is_base_of_v<KernelLogPipeProvider, 110 std::remove_reference_t<Args>> || 111 ...); 112 if constexpr (uses_kernel_log_pipe) { 113 return cmd.template addMultibinding<KernelLogPipeConsumer, Type>(); 114 } else { 115 return cmd; 116 } 117 } 118 }; 119 120 template <auto Fn> 121 using AutoCmd = GenericCommandImpl<Fn, decltype(Fn)>; 122 123 } // namespace cuttlefish 124