blob: 524c2e9cb98ded868b26057598e4795bf293b65a [file] [log] [blame]
// Copyright 2020 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.
#ifndef SRC_DEVELOPER_FORENSICS_CRASH_REPORTS_SNAPSHOT_COLLECTOR_H_
#define SRC_DEVELOPER_FORENSICS_CRASH_REPORTS_SNAPSHOT_COLLECTOR_H_
#include <lib/async/cpp/task.h>
#include <lib/async/dispatcher.h>
#include <lib/fpromise/promise.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/zx/time.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "src/developer/forensics/crash_reports/product.h"
#include "src/developer/forensics/crash_reports/queue.h"
#include "src/developer/forensics/crash_reports/report.h"
#include "src/developer/forensics/crash_reports/reporting_policy_watcher.h"
#include "src/developer/forensics/crash_reports/snapshot_store.h"
#include "src/developer/forensics/feedback/annotations/types.h"
#include "src/developer/forensics/feedback_data/data_provider.h"
#include "src/lib/timekeeper/clock.h"
namespace forensics {
namespace crash_reports {
// Manages the collection of snapshots.
//
// To limit memory usage, SnapshotCollector will return the same Uuid to all calls to GetUuid that
// occur within |shared_request_window_| of a fuchsia.feedback.DataProvider/GetSnapshot request.
class SnapshotCollector {
public:
SnapshotCollector(async_dispatcher_t* dispatcher, timekeeper::Clock* clock,
feedback_data::DataProviderInternal* data_provider,
SnapshotStore* snapshot_store, Queue* queue,
zx::duration shared_request_window);
// Returns a promise of a report. The report may have a snapshot uuid, with that snapshot
// containing the most up-to-date system data (a new snapshot will be created if all existing
// snapshots contain data that is out-of-date). No snapshot will be saved if |timeout| expires.
::fpromise::promise<Report> GetReport(zx::duration timeout,
fuchsia::feedback::CrashReport fidl_report,
ReportId report_id,
std::optional<timekeeper::time_utc> current_utc_time,
const Product& product, bool is_hourly_snapshot,
ReportingPolicy reporting_policy);
// Shuts down the snapshot manager by cancelling any pending FIDL calls and provides waiting
// clients with a UUID for a generic "shutdown" snapshot.
void Shutdown();
private:
// State associated with an async call to fuchsia.feedback.DataProvider/GetSnapshot. If a
// SnapshotRequest exists, it is implicitly pending.
struct SnapshotRequest {
~SnapshotRequest() {
for (auto& blocked_promise : blocked_promises) {
if (blocked_promise) {
blocked_promise.resume_task();
}
}
}
// The uuid of the request's snapshot.
std::string uuid;
// Ids of pending promises associated with this request. There should be one promise for each
// report using this snapshot request.
std::set<uint64_t> promise_ids;
// Promises that are waiting on the call to complete.
std::vector<::fpromise::suspended_task> blocked_promises;
// The actual request that we delay by |shared_request_window_| after the SnapshotRequest is
// created.
async::TaskClosure delayed_get_snapshot;
};
struct ReportResults {
// The uuid of the report's snapshot.
std::string uuid;
// The annotations manually added plus annotations extracted from the report's snapshot.
std::shared_ptr<feedback::Annotations> annotations;
};
// Determine if the most recent SnapshotRequest's delayed call to
// fuchsia.feedback.DataProvider/GetSnapshopt has executed.
bool UseLatestRequest() const;
// Find the Snapshot{Request,Data} with Uuid |uuid|. If none exists, return nullptr.
SnapshotRequest* FindSnapshotRequest(const std::string& uuid);
// Make a call to fuchsia.feedback.DataProvider/GetSnapshot, started at |start_time|, and return
// the Uuid of its eventual snapshot.
std::string MakeNewSnapshotRequest(zx::time start_time, zx::duration timeout);
// Use |fidl_snapshot| to update all snapshot-related state with Uuid |uuid|.
void CompleteWithSnapshot(const std::string& uuid, feedback::Annotations annotations,
fuchsia::feedback::Attachment archive);
// Retrieves the MissingSnapshot from the store and returns the combination of annotations and
// presence annotations.
feedback::Annotations GetMissingSnapshotAnnotations(const std::string& uuid);
async_dispatcher_t* dispatcher_;
std::shared_ptr<sys::ServiceDirectory> services_;
timekeeper::Clock* clock_;
feedback_data::DataProviderInternal* data_provider_;
SnapshotStore* snapshot_store_;
Queue* queue_;
zx::duration shared_request_window_;
std::vector<std::unique_ptr<SnapshotRequest>> snapshot_requests_;
std::map<ReportId, ReportResults> report_results_;
bool shutdown_{false};
};
} // namespace crash_reports
} // namespace forensics
#endif // SRC_DEVELOPER_FORENSICS_CRASH_REPORTS_SNAPSHOT_COLLECTOR_H_