1 // Copyright 2016 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef COMPONENTS_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_ 6 #define COMPONENTS_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_ 7 8 #include <map> 9 #include <memory> 10 11 #include "base/memory/ref_counted.h" 12 #include "base/memory/scoped_refptr.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/metrics/statistics_recorder.h" 15 #include "base/scoped_multi_source_observation.h" 16 #include "base/task/task_runner.h" 17 #include "base/threading/thread_checker.h" 18 #include "components/metrics/metrics_provider.h" 19 #include "content/public/browser/browser_child_process_observer.h" 20 #include "content/public/browser/render_process_host.h" 21 #include "content/public/browser/render_process_host_creation_observer.h" 22 #include "content/public/browser/render_process_host_observer.h" 23 24 namespace base { 25 class PersistentHistogramAllocator; 26 } 27 28 namespace metrics { 29 30 // SubprocessMetricsProvider gathers and merges histograms stored in shared 31 // memory segments between processes. Merging occurs when a process exits, 32 // when metrics are being collected for upload, or when something else needs 33 // combined metrics (such as the chrome://histograms page). 34 // TODO(crbug/1293026): Do not inherit MetricsProvider. 35 class SubprocessMetricsProvider 36 : public MetricsProvider, 37 public base::StatisticsRecorder::HistogramProvider, 38 public content::BrowserChildProcessObserver, 39 public content::RenderProcessHostCreationObserver, 40 public content::RenderProcessHostObserver { 41 public: 42 SubprocessMetricsProvider(const SubprocessMetricsProvider&) = delete; 43 SubprocessMetricsProvider& operator=(const SubprocessMetricsProvider&) = 44 delete; 45 46 // Creates the global instance. Returns false if the instance already exists. 47 static bool CreateInstance(); 48 49 // Returns the global instance. 50 static SubprocessMetricsProvider* GetInstance(); 51 52 // Merge histograms for all subprocesses. This is used by tests that don't 53 // have access to the internal instance of this class. 54 static void MergeHistogramDeltasForTesting( 55 bool async = false, 56 base::OnceClosure done_callback = base::DoNothing()); 57 58 private: 59 friend class SubprocessMetricsProviderTest; 60 61 // Wrapper to add reference counting to an allocator so that it is only 62 // released it when all tasks have finished with it. Note that this is 63 // RefCounted and not RefCountedThreadSafe, meaning that references should 64 // only be created/destroyed on the same sequence (the implementation has 65 // DCHECKs to enforce this). 66 class RefCountedAllocator : public base::RefCounted<RefCountedAllocator> { 67 public: 68 explicit RefCountedAllocator( 69 std::unique_ptr<base::PersistentHistogramAllocator> allocator); 70 71 RefCountedAllocator(const RefCountedAllocator& other) = delete; 72 RefCountedAllocator& operator=(const RefCountedAllocator& other) = delete; 73 allocator()74 base::PersistentHistogramAllocator* allocator() { return allocator_.get(); } 75 76 private: 77 friend class base::RefCounted<RefCountedAllocator>; 78 ~RefCountedAllocator(); 79 80 std::unique_ptr<base::PersistentHistogramAllocator> allocator_; 81 }; 82 83 // The global instance should be accessed through Get(). 84 SubprocessMetricsProvider(); 85 86 // This should never be deleted, as it handles subprocess metrics for the 87 // whole lifetime of the browser process. 88 ~SubprocessMetricsProvider() override; 89 90 // Indicates subprocess to be monitored with unique id for later reference. 91 // Metrics reporting will read histograms from it and upload them to UMA. 92 void RegisterSubprocessAllocator( 93 int id, 94 std::unique_ptr<base::PersistentHistogramAllocator> allocator); 95 96 // Indicates that a subprocess has exited and is thus finished with the 97 // allocator it was using. 98 void DeregisterSubprocessAllocator(int id); 99 100 // base::StatisticsRecorder::HistogramProvider: 101 void MergeHistogramDeltas(bool async, 102 base::OnceClosure done_callback) override; 103 104 // content::BrowserChildProcessObserver: 105 void BrowserChildProcessLaunchedAndConnected( 106 const content::ChildProcessData& data) override; 107 void BrowserChildProcessHostDisconnected( 108 const content::ChildProcessData& data) override; 109 void BrowserChildProcessCrashed( 110 const content::ChildProcessData& data, 111 const content::ChildProcessTerminationInfo& info) override; 112 void BrowserChildProcessKilled( 113 const content::ChildProcessData& data, 114 const content::ChildProcessTerminationInfo& info) override; 115 116 // content::RenderProcessHostCreationObserver: 117 void OnRenderProcessHostCreated(content::RenderProcessHost* host) override; 118 119 // content::RenderProcessHostObserver: 120 void RenderProcessReady(content::RenderProcessHost* host) override; 121 void RenderProcessExited( 122 content::RenderProcessHost* host, 123 const content::ChildProcessTerminationInfo& info) override; 124 void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; 125 126 // Re-creates |sequenced_task_runner_|. Used for testing. 127 void RecreateTaskRunnerForTesting(); 128 129 // Merges all histograms of |allocator| to the global StatisticsRecorder. This 130 // is called periodically during UMA metrics collection (if enabled) and 131 // possibly on-demand for other purposes. May be called on a background 132 // thread. 133 static void MergeHistogramDeltasFromAllocator(int id, 134 RefCountedAllocator* allocator); 135 136 // Merges all histograms of the |allocators| to the global StatisticsRecorder. 137 // Does not have any form of ownership on the allocators. May be called on a 138 // background thread. 139 using AllocatorByIdMap = std::map<int, scoped_refptr<RefCountedAllocator>>; 140 static void MergeHistogramDeltasFromAllocators(AllocatorByIdMap* allocators); 141 142 // Callback for when MergeHistogramDeltasFromAllocator() is called in a 143 // background thread. 144 static void OnMergeHistogramDeltasFromAllocator( 145 scoped_refptr<RefCountedAllocator> allocator); 146 147 // Callback for when MergeHistogramDeltasFromAllocators() is called in a 148 // background thread. 149 static void OnMergeHistogramDeltasFromAllocators( 150 std::unique_ptr<AllocatorByIdMap> allocators, 151 base::OnceClosure done_callback); 152 153 THREAD_CHECKER(thread_checker_); 154 155 // All of the shared-persistent-allocators for known sub-processes. 156 AllocatorByIdMap allocators_by_id_; 157 158 // Track all observed render processes to un-observe them on exit. 159 // TODO(crbug/1293026): Since this class should be leaky, it is not 160 // semantically correct to have a "scoped" member field here. Replace this 161 // with something like a set. 162 base::ScopedMultiSourceObservation<content::RenderProcessHost, 163 content::RenderProcessHostObserver> 164 scoped_observations_{this}; 165 166 // Used to asynchronously merge metrics from subprocesses that have exited. 167 scoped_refptr<base::TaskRunner> task_runner_; 168 169 base::WeakPtrFactory<SubprocessMetricsProvider> weak_ptr_factory_{this}; 170 }; 171 172 } // namespace metrics 173 174 #endif // COMPONENTS_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_ 175