blob: 806929e265f2566fac0c0fad0ae0315779170c5c [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_UKM_SINGULAR_UKM_ENTRY_H_
#define COMPONENTS_UKM_SINGULAR_UKM_ENTRY_H_
#include <memory>
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace ukm {
template <typename>
class SingularUkmEntry;
// Creates the SingularUkmInterface receiver.
void CreateSingularUkmInterface(
mojo::PendingReceiver<mojom::SingularUkmInterface> receiver);
// Singular UKM Entries are UKM Entries that can be 'recorded' multiple times
// but only the last one will be recorded by the UKM Service. While not
// currently supported, it is designed to support entries from multiple
// processes and still record the UkmEntry in the event that the remote process
// is exited. If the browser process crashes then all entries that haven't been
// saved to a log are lost.
//
// Notice: This currently only works within the browser process. Multi-process
// is not implemented and changes need to be added to the startup
// process of the desired process.
//
// Create a new UKM entry as so:
//
// std::unique_ptr<SingularUkmEntry<AdFrameLoad>> entry =
// SingularUkmEntry<AdFrameLoad>::Create(source_id);
//
// {
// SingularUkmEntry<AdFrameLoad>::EntryBuilder builder = entry->Builder();
// builder->SetCpuTime_PeakWindowedPercent(cpu_time_pwp1);
// builder->SetCpuTime_Total(total_cpu_time1);
// }
// {
// SingularUkmEntry<AdFrameLoad>::EntryBuilder builder = entry->Builder();
// builder->SetCpuTime_PeakWindowedPercent(cpu_time_pwp2);
// builder->SetCpuTime_Total(total_cpu_time2);
// }
//
// In the example above, only cpu_time_pwp2 and total_cpu_time2 will be recorded
// by the UKM service when `entry` is destroyed. Destructor of `builder` will
// update the `entry`.
//
// Note:
// - Use arrow operator on the builder to access the underlying UkmEntry. This
// will give access to UkmEntry's methods.
// - When a EntryBuilder is destroyed or goes out of scope, the corresponding
// UkmEntry is committed as the latest to be recorded.
// - A SingularUkmEntry and the EntryBuilders created from it must be used on
// the same sequence it was created.
// - The UkmEntry will not be recorded until the SingularUkmEntry is destroyed.
// - The SingularUkmEntry must outlive all EntryBuilder's created from it.
// - All desired metrics must be set by the EntryBuilder to be recorded.
//
// Wrapper class to associate an UkmEntry type with an interface and source id.
// Template UkmEntry is expected to have a base class of UkmEntryBuilderBase.
// See tools/metrics/ukm/ukm.xml for entry definitions.
template <typename UkmEntry>
class SingularUkmEntry {
public:
// Creates a new SingularUkmEntry.
static std::unique_ptr<SingularUkmEntry<UkmEntry>> Create(
SourceId source_id) {
mojo::PendingRemote<mojom::SingularUkmInterface> remote;
CreateSingularUkmInterface(remote.InitWithNewPipeAndPassReceiver());
return base::WrapUnique(
new SingularUkmEntry<UkmEntry>(source_id, std::move(remote)));
}
SingularUkmEntry(const SingularUkmEntry<UkmEntry>&) = delete;
SingularUkmEntry& operator=(const SingularUkmEntry<UkmEntry>&) = delete;
~SingularUkmEntry() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
// Provides an interface to build the UkmEntry. The built UkmEntry is
// submitted to the interface on destruction.
class EntryBuilder {
public:
EntryBuilder(const EntryBuilder&) = delete;
EntryBuilder& operator=(const EntryBuilder&) = delete;
~EntryBuilder() {
DCHECK_CALLED_ON_VALID_SEQUENCE(singular_ukm_entry_->sequence_checker_);
singular_ukm_entry_->interface_->Submit(entry_.TakeEntry());
}
// Provides a simple interface to interact with the underlying UkmEntry.
UkmEntry* operator->() { return &entry_; }
private:
friend class SingularUkmEntry<UkmEntry>;
EntryBuilder(SourceId source_id,
SingularUkmEntry<UkmEntry>& singular_ukm_entry)
: entry_(source_id), singular_ukm_entry_(&singular_ukm_entry) {}
// The current entry being built.
UkmEntry entry_;
// The SingularUkmEntry that created |this|. It provides the Mojo interface
// to submit completed UKMEntryies.
raw_ptr<SingularUkmEntry<UkmEntry>> singular_ukm_entry_;
};
// Creates an EntryBuilder. EntryBuilders are used to build an UkmEntry and
// submit it to the receiver.
EntryBuilder Builder() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return EntryBuilder(source_id_, *this);
}
private:
SingularUkmEntry(SourceId source_id,
mojo::PendingRemote<mojom::SingularUkmInterface> interface)
: source_id_(source_id), interface_(std::move(interface)) {
CHECK(interface_);
}
// The SourceId to be used by new entries.
SourceId source_id_;
mojo::Remote<mojom::SingularUkmInterface> interface_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace ukm
#endif // COMPONENTS_UKM_SINGULAR_UKM_ENTRY_H_