1 // Copyright 2019 The Chromium Authors. All rights reserved. 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 CONTENT_BROWSER_RENDERER_HOST_BACK_FORWARD_CACHE_METRICS_H_ 6 #define CONTENT_BROWSER_RENDERER_HOST_BACK_FORWARD_CACHE_METRICS_H_ 7 8 #include <bitset> 9 #include <set> 10 11 #include "base/macros.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/optional.h" 14 #include "base/strings/string_piece.h" 15 #include "base/time/tick_clock.h" 16 #include "base/time/time.h" 17 #include "content/browser/renderer_host/should_swap_browsing_instance.h" 18 #include "content/common/content_export.h" 19 20 namespace url { 21 class Origin; 22 } 23 24 namespace content { 25 class BackForwardCacheCanStoreDocumentResult; 26 class NavigationEntryImpl; 27 class NavigationRequest; 28 class RenderFrameHostImpl; 29 struct LoadCommittedDetails; 30 31 // Helper class for recording metrics around history navigations. 32 // Associated with a main frame document and shared between all 33 // NavigationEntries with the same document_sequence_number for the main 34 // document. 35 // 36 // TODO(altimin, crbug.com/933147): Remove this class after we are done 37 // with implementing back-forward cache. 38 class BackForwardCacheMetrics 39 : public base::RefCounted<BackForwardCacheMetrics> { 40 public: 41 // Please keep in sync with BackForwardCacheNotRestoredReason in 42 // tools/metrics/histograms/enums.xml. These values should not be renumbered. 43 enum class NotRestoredReason : uint8_t { 44 kNotMainFrame = 0, 45 // BackForwardCache is disabled due to low memory device, base::Feature or 46 // command line. Note that the more specific NotRestoredReasons 47 // kBackForwardCacheDisabledByLowMemory and 48 // kBackForwardCacheDisabledByCommandLine will also be set as other reasons 49 // along with this when appropriate. 50 kBackForwardCacheDisabled = 1, 51 kRelatedActiveContentsExist = 2, 52 kHTTPStatusNotOK = 3, 53 kSchemeNotHTTPOrHTTPS = 4, 54 kLoading = 5, 55 kWasGrantedMediaAccess = 6, 56 kBlocklistedFeatures = 7, 57 kDisableForRenderFrameHostCalled = 8, 58 kDomainNotAllowed = 9, 59 kHTTPMethodNotGET = 10, 60 kSubframeIsNavigating = 11, 61 kTimeout = 12, 62 kCacheLimit = 13, 63 kJavaScriptExecution = 14, 64 kRendererProcessKilled = 15, 65 kRendererProcessCrashed = 16, 66 // 17: Dialogs are no longer a reason to exclude from BackForwardCache 67 kGrantedMediaStreamAccess = 18, 68 kSchedulerTrackedFeatureUsed = 19, 69 kConflictingBrowsingInstance = 20, 70 kCacheFlushed = 21, 71 kServiceWorkerVersionActivation = 22, 72 kSessionRestored = 23, 73 kUnknown = 24, 74 kServiceWorkerPostMessage = 25, 75 kEnteredBackForwardCacheBeforeServiceWorkerHostAdded = 26, 76 kRenderFrameHostReused_SameSite = 27, 77 kRenderFrameHostReused_CrossSite = 28, 78 kNotMostRecentNavigationEntry = 29, 79 kServiceWorkerClaim = 30, 80 kIgnoreEventAndEvict = 31, 81 kHaveInnerContents = 32, 82 kTimeoutPuttingInCache = 33, 83 // BackForwardCache is disabled due to low memory device. 84 kBackForwardCacheDisabledByLowMemory = 34, 85 // BackForwardCache is disabled due to command-line switch (may include 86 // cases where the embedder disabled it due to, e.g., enterprise policy). 87 kBackForwardCacheDisabledByCommandLine = 35, 88 kFrameTreeNodeStateReset = 36, 89 kNetworkRequestDatapipeDrained = 37, 90 kNetworkRequestRedirected = 38, 91 kNetworkRequestTimeout = 39, 92 kNetworkExceedsBufferLimit = 40, 93 kNavigationCancelledWhileRestoring = 41, 94 kMaxValue = kNavigationCancelledWhileRestoring, 95 }; 96 97 using NotRestoredReasons = 98 std::bitset<static_cast<size_t>(NotRestoredReason::kMaxValue) + 1ul>; 99 100 // Please keep in sync with BackForwardCacheHistoryNavigationOutcome in 101 // tools/metrics/histograms/enums.xml. These values should not be renumbered. 102 enum class HistoryNavigationOutcome { 103 kRestored = 0, 104 kNotRestored = 1, 105 kMaxValue = kNotRestored, 106 }; 107 108 // Please keep in sync with BackForwardCacheEvictedAfterDocumentRestoredReason 109 // in tools/metrics/histograms/enums.xml. These values should not be 110 // renumbered. 111 enum class EvictedAfterDocumentRestoredReason { 112 kRestored = 0, 113 kByJavaScript = 1, 114 kMaxValue = kByJavaScript, 115 }; 116 117 // Please keep in sync with BackForwardCacheReloadsAndHistoryNavigations 118 // in tools/metrics/histograms/enums.xml. These values should not be 119 // renumbered. 120 enum class ReloadsAndHistoryNavigations { 121 kHistoryNavigation = 0, 122 kReloadAfterHistoryNavigation = 1, 123 kMaxValue = kReloadAfterHistoryNavigation, 124 }; 125 126 // Please keep in sync with BackForwardCacheReloadsAfterHistoryNavigation 127 // in tools/metrics/histograms/enums.xml. These values should not be 128 // renumbered. 129 enum class ReloadsAfterHistoryNavigation { 130 kNotServedFromBackForwardCache = 0, 131 kServedFromBackForwardCache = 1, 132 kMaxValue = kServedFromBackForwardCache, 133 }; 134 135 // Creates a potential new metrics object for the navigation. 136 // Note that this object will not be used if the entry we are navigating to 137 // already has the BackForwardCacheMetrics object (which happens for history 138 // navigations). 139 // 140 // |document_sequence_number| is the sequence number of the document 141 // associated with the document associated with the navigating frame and it is 142 // ignored if the navigating frame is not a main one. 143 static scoped_refptr<BackForwardCacheMetrics> 144 CreateOrReuseBackForwardCacheMetrics( 145 NavigationEntryImpl* currently_committed_entry, 146 bool is_main_frame_navigation, 147 int64_t document_sequence_number); 148 149 // Records when the page is evicted after the document is restored e.g. when 150 // the race condition by JavaScript happens. 151 static void RecordEvictedAfterDocumentRestored( 152 EvictedAfterDocumentRestoredReason reason); 153 154 // Notifies that the main frame has started a navigation to an entry 155 // associated with |this|. 156 // 157 // This is the point in time that a back-forward cache hit could be shown to 158 // the user. 159 // 160 // Note that in some cases (synchronous renderer-initiated navigations 161 // which create navigation entry only when committed) this call might 162 // be missing, but they should not matter for bfcache. 163 void MainFrameDidStartNavigationToDocument(); 164 165 // Notifies that an associated entry has committed a navigation. 166 // |back_forward_cache_allowed| indicates whether back-forward cache is 167 // allowed for the URL of |navigation_request|. 168 void DidCommitNavigation(NavigationRequest* navigation_request, 169 bool back_forward_cache_allowed); 170 171 // Records when another navigation commits away from the most recent entry 172 // associated with |this|. This is the point in time that the previous 173 // document could enter the back-forward cache. 174 // |new_main_document| points to the newly committed RFH, which might or might 175 // not be the same as the RFH for the old document. 176 void MainFrameDidNavigateAwayFromDocument( 177 RenderFrameHostImpl* new_main_document, 178 LoadCommittedDetails* details, 179 NavigationRequest* navigation); 180 181 // Snapshots the state of the features active on the page before closing it. 182 // It should be called at the same time when the document might have been 183 // placed in the back-forward cache. 184 void RecordFeatureUsage(RenderFrameHostImpl* main_frame); 185 186 // Marks when the page is not cached, or evicted. This information is useful 187 // e.g., to prioritize the tasks to improve cache-hit rate. 188 void MarkNotRestoredWithReason( 189 const BackForwardCacheCanStoreDocumentResult& can_store); 190 191 // Injects a clock for mocking time. 192 // Should be called only from the UI thread. 193 CONTENT_EXPORT static void OverrideTimeForTesting(base::TickClock* clock); 194 195 private: 196 friend class base::RefCounted<BackForwardCacheMetrics>; 197 198 explicit BackForwardCacheMetrics(int64_t document_sequence_number); 199 200 ~BackForwardCacheMetrics(); 201 202 // Recursively collects the feature usage information from the subtree 203 // of a given frame. 204 void CollectFeatureUsageFromSubtree(RenderFrameHostImpl* rfh, 205 const url::Origin& main_frame_origin); 206 207 // Dumps the current recorded information. 208 // |back_forward_cache_allowed| indicates whether back-forward cache is 209 // allowed for the URL of |navigation_request|. 210 void RecordMetricsForHistoryNavigationCommit( 211 NavigationRequest* navigation, 212 bool back_forward_cache_allowed) const; 213 214 // Record metrics for the number of reloads after history navigation. In 215 // particular we are interested in number of reloads after a restore from 216 // the back-forward cache as a proxy for detecting whether the page was 217 // broken or not. 218 void RecordHistogramForReloadsAndHistoryNavigations( 219 bool is_reload, 220 bool back_forward_cache_allowed) const; 221 222 // Record additional reason why navigation was not served from bfcache which 223 // are known only at the commit time. 224 void UpdateNotRestoredReasonsForNavigation(NavigationRequest* navigation); 225 226 bool ShouldRecordBrowsingInstanceNotSwappedReason() const; 227 228 void RecordHistoryNavigationUkm(NavigationRequest* navigation); 229 230 // Main frame document sequence number that identifies all NavigationEntries 231 // this metrics object is associated with. 232 const int64_t document_sequence_number_; 233 234 // NavigationHandle's ID for the last main frame navigation. This is updated 235 // for a main frame, not-same-document navigation. 236 // 237 // Should not be confused with NavigationEntryId. 238 int64_t last_committed_cross_document_main_frame_navigation_id_ = -1; 239 240 int64_t last_committed_navigation_entry_id_ = -1; 241 242 uint64_t main_frame_features_ = 0; 243 // We record metrics for same-origin frames and cross-origin frames 244 // differently as we might want to apply different policies for them, 245 // especially for the things around web platform compatibility (e.g. ignore 246 // unload handlers in cross-origin iframes but not in same-origin). The 247 // details are still subject to metrics, however. NOTE: This is not related to 248 // which process these frames are hosted in. 249 uint64_t same_origin_frames_features_ = 0; 250 uint64_t cross_origin_frames_features_ = 0; 251 252 base::Optional<base::TimeTicks> started_navigation_timestamp_; 253 base::Optional<base::TimeTicks> navigated_away_from_main_document_timestamp_; 254 255 NotRestoredReasons not_restored_reasons_; 256 uint64_t blocklisted_features_ = 0; 257 base::Optional<ShouldSwapBrowsingInstance> 258 browsing_instance_not_swapped_reason_; 259 260 // The reasons given at BackForwardCache::DisableForRenderFrameHost. These are 261 // a further breakdown of NotRestoredReason::kDisableForRenderFrameHostCalled. 262 std::set<std::string> disabled_reasons_; 263 264 // This value is updated only for navigations which are not same-document and 265 // main-frame navigations. 266 bool previous_navigation_is_history_ = false; 267 bool previous_navigation_is_served_from_bfcache_ = false; 268 269 base::Optional<base::TimeTicks> renderer_killed_timestamp_; 270 271 DISALLOW_COPY_AND_ASSIGN(BackForwardCacheMetrics); 272 }; 273 274 } // namespace content 275 276 #endif // CONTENT_BROWSER_RENDERER_HOST_BACK_FORWARD_CACHE_METRICS_H_ 277