blob: 4f34ac245758af1ccb5688fd55e02ed087ab2025 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE
// file.
#include "src/developer/feedback/feedback_agent/annotations/annotation_provider_factory.h"
#include <memory>
#include "src/developer/feedback/feedback_agent/annotations/board_info_provider.h"
#include "src/developer/feedback/feedback_agent/annotations/board_name_provider.h"
#include "src/developer/feedback/feedback_agent/annotations/build_info_provider.h"
#include "src/developer/feedback/feedback_agent/annotations/channel_provider.h"
#include "src/developer/feedback/feedback_agent/annotations/product_info_provider.h"
#include "src/developer/feedback/feedback_agent/annotations/time_provider.h"
#include "src/developer/feedback/feedback_agent/constants.h"
#include "src/developer/feedback/utils/cobalt.h"
#include "src/lib/syslog/cpp/logger.h"
#include "src/lib/timekeeper/system_clock.h"
namespace feedback {
namespace {
// Generate a vector that contains all of the values of an enum class.
template <typename Enum, Enum First, Enum Last>
std::vector<Enum> AllEnumValues() {
std::vector<Enum> values(static_cast<size_t>(Last) - static_cast<size_t>(First) + 1);
std::generate(values.begin(), values.end(),
[n = static_cast<size_t>(First)]() mutable { return static_cast<Enum>(n++); });
return values;
}
// The type of annotations.
enum class AnnotationType {
BoardName = 0,
BuildInfo,
Channel,
HardwareBoardInfo,
HardwareProductInfo,
Time,
};
const auto GetAnnotationTypes =
AllEnumValues<AnnotationType, AnnotationType::BoardName, AnnotationType::Time>;
std::set<std::string> GetSupportedAnnotations(const AnnotationType type) {
switch (type) {
case AnnotationType::BoardName:
return BoardNameProvider::GetSupportedAnnotations();
case AnnotationType::BuildInfo:
return BuildInfoProvider::GetSupportedAnnotations();
case AnnotationType::Channel:
return ChannelProvider::GetSupportedAnnotations();
case AnnotationType::HardwareBoardInfo:
return BoardInfoProvider::GetSupportedAnnotations();
case AnnotationType::HardwareProductInfo:
return ProductInfoProvider::GetSupportedAnnotations();
case AnnotationType::Time:
return TimeProvider::GetSupportedAnnotations();
}
}
std::set<std::string> AnnotationsToCollect(const AnnotationType type,
const std::set<std::string>& allowlist) {
const std::set<std::string> supported = GetSupportedAnnotations(type);
std::vector<std::string> intersection;
std::set_intersection(allowlist.begin(), allowlist.end(), supported.begin(), supported.end(),
std::back_inserter(intersection));
return std::set(intersection.begin(), intersection.end());
}
std::unique_ptr<AnnotationProvider> GetProvider(const AnnotationType type,
const std::set<std::string>& annotations,
async_dispatcher_t* dispatcher,
std::shared_ptr<sys::ServiceDirectory> services,
const zx::duration timeout,
std::shared_ptr<Cobalt> cobalt) {
switch (type) {
case AnnotationType::BoardName:
return std::make_unique<BoardNameProvider>();
case AnnotationType::BuildInfo:
return std::make_unique<BuildInfoProvider>(annotations);
case AnnotationType::Channel:
return std::make_unique<ChannelProvider>(dispatcher, services, timeout, std::move(cobalt));
case AnnotationType::HardwareBoardInfo:
return std::make_unique<BoardInfoProvider>(annotations, dispatcher, services, timeout,
std::move(cobalt));
case AnnotationType::HardwareProductInfo:
return std::make_unique<ProductInfoProvider>(annotations, dispatcher, services, timeout,
std::move(cobalt));
case AnnotationType::Time:
return std::make_unique<TimeProvider>(annotations,
std::make_unique<timekeeper::SystemClock>());
}
}
std::set<std::string> AddIfAnnotationsIntersect(
const AnnotationType type, const std::set<std::string>& allowlist,
async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services,
const zx::duration timeout, std::shared_ptr<Cobalt> cobalt,
std::vector<std::unique_ptr<AnnotationProvider>>* providers) {
auto annotations = AnnotationsToCollect(type, allowlist);
if (!annotations.empty()) {
providers->push_back(
GetProvider(type, annotations, dispatcher, services, timeout, std::move(cobalt)));
}
return annotations;
}
} // namespace
std::vector<std::unique_ptr<AnnotationProvider>> GetProviders(
const std::set<std::string>& allowlist, async_dispatcher_t* dispatcher,
std::shared_ptr<sys::ServiceDirectory> services, const zx::duration timeout,
std::shared_ptr<Cobalt> cobalt) {
static auto annotation_types = GetAnnotationTypes();
std::set<std::string> ignored_annotations = allowlist;
std::vector<std::unique_ptr<AnnotationProvider>> providers;
for (const auto& type : annotation_types) {
const auto annotations = AddIfAnnotationsIntersect(type, allowlist, dispatcher, services,
timeout, cobalt, &providers);
for (const auto& annotation : annotations) {
ignored_annotations.erase(annotation);
}
}
for (const auto& annotation : ignored_annotations) {
FX_LOGS(WARNING) << "Annotation " << annotation
<< " is not supported and will not be collected";
}
return providers;
}
} // namespace feedback