blob: 5113719cae95feaec54d16c1ed6a01b97bbbc272 [file] [log] [blame]
// Copyright 2016 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_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_
#define COMPONENTS_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_
#include <map>
#include <memory>
#include "base/containers/variant_map.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/statistics_recorder.h"
#include "base/scoped_multi_source_observation.h"
#include "base/task/task_runner.h"
#include "base/threading/thread_checker.h"
#include "base/types/pass_key.h"
#include "components/metrics/metrics_provider.h"
#include "content/public/browser/browser_child_process_observer.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_creation_observer.h"
#include "content/public/browser/render_process_host_observer.h"
namespace base {
class PersistentHistogramAllocator;
}
namespace metrics {
// SubprocessMetricsProvider gathers and merges histograms stored in shared
// memory segments between processes. Merging occurs when a process exits,
// when metrics are being collected for upload, or when something else needs
// combined metrics (such as the chrome://histograms page).
// TODO(crbug.com/40213327): Do not inherit MetricsProvider.
class SubprocessMetricsProvider
: public MetricsProvider,
public base::StatisticsRecorder::HistogramProvider,
public content::BrowserChildProcessObserver,
public content::RenderProcessHostCreationObserver,
public content::RenderProcessHostObserver {
public:
using PassKey = base::PassKey<SubprocessMetricsProvider>;
SubprocessMetricsProvider(const SubprocessMetricsProvider&) = delete;
SubprocessMetricsProvider& operator=(const SubprocessMetricsProvider&) =
delete;
// Creates the global instance. Returns false if the instance already exists.
static bool CreateInstance();
// Returns the global instance.
static SubprocessMetricsProvider* GetInstance();
// Merge histograms for all subprocesses. This is used by tests that don't
// have access to the internal instance of this class.
static void MergeHistogramDeltasForTesting(
bool async = false,
base::OnceClosure done_callback = base::DoNothing());
// Indicates subprocess to be monitored with unique id for later reference.
// Metrics reporting will read histograms from it and upload them to UMA.
void RegisterSubprocessAllocator(
int id,
std::unique_ptr<base::PersistentHistogramAllocator> allocator);
// Indicates that a subprocess has exited and is thus finished with the
// allocator it was using.
void DeregisterSubprocessAllocator(int id);
private:
friend class SubprocessMetricsProviderTest;
// Wrapper to add reference counting to an allocator so that it is only
// released it when all tasks have finished with it. Note that this is
// RefCounted and not RefCountedThreadSafe, meaning that references should
// only be created/destroyed on the same sequence (the implementation has
// DCHECKs to enforce this).
class RefCountedAllocator : public base::RefCounted<RefCountedAllocator> {
public:
explicit RefCountedAllocator(
std::unique_ptr<base::PersistentHistogramAllocator> allocator);
RefCountedAllocator(const RefCountedAllocator& other) = delete;
RefCountedAllocator& operator=(const RefCountedAllocator& other) = delete;
base::PersistentHistogramAllocator* allocator() { return allocator_.get(); }
private:
friend class base::RefCounted<RefCountedAllocator>;
~RefCountedAllocator();
std::unique_ptr<base::PersistentHistogramAllocator> allocator_;
};
// The global instance should be accessed through Get().
SubprocessMetricsProvider();
// This should never be deleted, as it handles subprocess metrics for the
// whole lifetime of the browser process.
~SubprocessMetricsProvider() override;
// base::StatisticsRecorder::HistogramProvider:
void MergeHistogramDeltas(bool async,
base::OnceClosure done_callback) override;
// content::BrowserChildProcessObserver:
void BrowserChildProcessLaunchedAndConnected(
const content::ChildProcessData& data) override;
void BrowserChildProcessHostDisconnected(
const content::ChildProcessData& data) override;
void BrowserChildProcessCrashed(
const content::ChildProcessData& data,
const content::ChildProcessTerminationInfo& info) override;
void BrowserChildProcessKilled(
const content::ChildProcessData& data,
const content::ChildProcessTerminationInfo& info) override;
// content::RenderProcessHostCreationObserver:
void OnRenderProcessHostCreated(content::RenderProcessHost* host) override;
// content::RenderProcessHostObserver:
void RenderProcessReady(content::RenderProcessHost* host) override;
void RenderProcessExited(
content::RenderProcessHost* host,
const content::ChildProcessTerminationInfo& info) override;
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
// Re-creates |sequenced_task_runner_|. Used for testing.
void RecreateTaskRunnerForTesting();
// Merges all histograms of |allocator| to the global StatisticsRecorder. This
// is called periodically during UMA metrics collection (if enabled) and
// possibly on-demand for other purposes. May be called on a background
// thread.
static void MergeHistogramDeltasFromAllocator(int id,
RefCountedAllocator* allocator);
// Merges all histograms of the |allocators| to the global StatisticsRecorder.
// Does not have any form of ownership on the allocators. May be called on a
// background thread.
using AllocatorByIdMap =
base::VariantMap<int, scoped_refptr<RefCountedAllocator>>;
static void MergeHistogramDeltasFromAllocators(AllocatorByIdMap* allocators);
// Callback for when MergeHistogramDeltasFromAllocator() is called in a
// background thread.
static void OnMergeHistogramDeltasFromAllocator(
scoped_refptr<RefCountedAllocator> allocator);
// Callback for when MergeHistogramDeltasFromAllocators() is called in a
// background thread.
static void OnMergeHistogramDeltasFromAllocators(
std::unique_ptr<AllocatorByIdMap> allocators,
base::OnceClosure done_callback);
THREAD_CHECKER(thread_checker_);
// All of the shared-persistent-allocators for known sub-processes.
AllocatorByIdMap allocators_by_id_;
// Track all observed render processes to un-observe them on exit.
// TODO(crbug.com/40213327): Since this class should be leaky, it is not
// semantically correct to have a "scoped" member field here. Replace this
// with something like a set.
base::ScopedMultiSourceObservation<content::RenderProcessHost,
content::RenderProcessHostObserver>
scoped_observations_{this};
// Used to asynchronously merge metrics from subprocesses that have exited.
scoped_refptr<base::TaskRunner> task_runner_;
base::WeakPtrFactory<SubprocessMetricsProvider> weak_ptr_factory_{this};
};
} // namespace metrics
#endif // COMPONENTS_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_