blob: d1a29fb8e3d16783944bccdec123dd59ec3b0c74 [file] [log] [blame]
// Copyright 2021 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/forensics/feedback_data/annotations/timezone_provider.h"
#include <lib/async/cpp/task.h>
#include <lib/fit/function.h>
#include "src/developer/forensics/feedback_data/annotations/utils.h"
#include "src/developer/forensics/feedback_data/constants.h"
namespace forensics::feedback_data {
namespace {
static const AnnotationKeys* kSupportedAnnotations = new AnnotationKeys({
kAnnotationSystemTimezonePrimary,
});
} // namespace
TimezoneProvider::TimezoneProvider(async_dispatcher_t* dispatcher,
std::shared_ptr<sys::ServiceDirectory> services)
: dispatcher_(dispatcher),
services_(services),
bridges_(dispatcher_),
backoff_(/*initial_delay=*/zx::sec(10), /*retry_factor=*/2u,
/*max_delay=*/zx::hour(1)) {
services_->Connect(property_provider_ptr_.NewRequest(dispatcher_));
property_provider_ptr_.events().OnChange =
::fit::bind_member(this, &TimezoneProvider::GetTimezone);
property_provider_ptr_.set_error_handler(::fit::bind_member(this, &TimezoneProvider::OnError));
GetTimezone();
}
::fpromise::promise<Annotations> TimezoneProvider::GetAnnotations(zx::duration timeout,
const AnnotationKeys& allowlist) {
const AnnotationKeys annotations_to_get = RestrictAllowlist(allowlist, *kSupportedAnnotations);
if (annotations_to_get.empty()) {
return ::fpromise::make_result_promise<Annotations>(::fpromise::ok<Annotations>({}));
}
if (timezone_.has_value()) {
return ::fpromise::make_result_promise<Annotations>(::fpromise::ok<Annotations>({
{kAnnotationSystemTimezonePrimary, *timezone_},
}));
}
const uint64_t id = bridges_.NewBridgeForTask("GetTimezone");
return bridges_.WaitForDone(id, fit::Timeout(timeout))
.then([this, id](const ::fpromise::result<std::string, Error>& result) {
AnnotationOr annotation(Error::kNotSet);
if (result.is_ok()) {
annotation = result.value();
} else {
annotation = result.error();
}
bridges_.Delete(id);
return ::fpromise::make_result_promise<Annotations>(::fpromise::ok<Annotations>({
{kAnnotationSystemTimezonePrimary, std::move(annotation)},
}));
});
}
void TimezoneProvider::GetTimezone() {
FX_CHECK(property_provider_ptr_.is_bound());
property_provider_ptr_->GetProfile([this](const fuchsia::intl::Profile profile) {
if (!profile.has_time_zones()) {
return;
}
const auto& time_zones = profile.time_zones();
if (time_zones.empty()) {
return;
}
timezone_ = time_zones.front().id;
bridges_.CompleteAllOk(*timezone_);
});
}
void TimezoneProvider::OnError(const zx_status_t status) {
bridges_.CompleteAllError(Error::kConnectionError);
async::PostDelayedTask(
dispatcher_,
[weak_ptr = weak_ptr_factory_.GetWeakPtr()]() {
if (!weak_ptr) {
return;
}
auto& thiz = *weak_ptr;
thiz.services_->Connect(thiz.property_provider_ptr_.NewRequest(thiz.dispatcher_));
thiz.GetTimezone();
thiz.backoff_.Reset();
},
backoff_.GetNext());
}
} // namespace forensics::feedback_data