web_memory_impl.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Copyright 2020 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. #include "components/performance_manager/v8_memory/web_memory_impl.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback.h"
  9. #include "base/check.h"
  10. #include "base/command_line.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "components/performance_manager/public/graph/frame_node.h"
  13. #include "components/performance_manager/public/graph/graph.h"
  14. #include "components/performance_manager/public/graph/page_node.h"
  15. #include "components/performance_manager/public/graph/process_node.h"
  16. #include "components/performance_manager/public/performance_manager.h"
  17. #include "components/performance_manager/public/render_frame_host_proxy.h"
  18. #include "components/performance_manager/public/v8_memory/web_memory.h"
  19. #include "components/performance_manager/v8_memory/web_memory_aggregator.h"
  20. #include "content/public/browser/browser_task_traits.h"
  21. #include "content/public/browser/browser_thread.h"
  22. #include "content/public/browser/render_frame_host.h"
  23. #include "content/public/browser/render_process_host.h"
  24. #include "content/public/common/content_switches.h"
  25. #include "third_party/blink/public/common/features.h"
  26. #include "url/gurl.h"
  27. #include "url/origin.h"
  28. namespace performance_manager {
  29. namespace v8_memory {
  30. namespace {
  31. mojom::WebMemoryMeasurementPtr BuildMemoryUsageResult(
  32. const blink::LocalFrameToken& frame_token,
  33. const ProcessNode* process_node) {
  34. const auto& frame_nodes = process_node->GetFrameNodes();
  35. const auto it = std::find_if(frame_nodes.begin(), frame_nodes.end(),
  36. [frame_token](const FrameNode* node) {
  37. return node->GetFrameToken() == frame_token;
  38. });
  39. if (it == frame_nodes.end()) {
  40. // The frame no longer exists.
  41. return mojom::WebMemoryMeasurement::New();
  42. }
  43. return WebMemoryAggregator(*it).AggregateMeasureMemoryResult();
  44. }
  45. v8_memory::V8DetailedMemoryRequest::MeasurementMode
  46. WebMeasurementModeToRequestMeasurementMode(
  47. mojom::WebMemoryMeasurement::Mode mode) {
  48. switch (mode) {
  49. case mojom::WebMemoryMeasurement::Mode::kDefault:
  50. return v8_memory::V8DetailedMemoryRequest::MeasurementMode::kDefault;
  51. case mojom::WebMemoryMeasurement::Mode::kEager:
  52. return v8_memory::V8DetailedMemoryRequest::MeasurementMode::
  53. kEagerForTesting;
  54. }
  55. }
  56. // Checks if the frame referenced by |rfh_proxy| is crossOriginIsolated. If so,
  57. // invokes |measure_memory_callback| on the PM sequences. If not, invokes
  58. // |bad_message_callback| instead. If the frame disappears at any point, does
  59. // nothing.
  60. void CheckIsCrossOriginIsolatedOnUISeq(
  61. const RenderFrameHostProxy& rfh_proxy,
  62. WebMeasureMemorySecurityChecker::MeasureMemoryCallback
  63. measure_memory_callback,
  64. mojo::ReportBadMessageCallback bad_message_callback) {
  65. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  66. content::RenderFrameHost* rfh = rfh_proxy.Get();
  67. if (!rfh) {
  68. // Frame was deleted before the task ran.
  69. return;
  70. }
  71. if (rfh->GetWebExposedIsolationLevel() ==
  72. content::RenderFrameHost::WebExposedIsolationLevel::kNotIsolated &&
  73. !base::CommandLine::ForCurrentProcess()->HasSwitch(
  74. switches::kDisableWebSecurity)) {
  75. std::move(bad_message_callback)
  76. .Run("Requesting frame must be cross-origin isolated.");
  77. return;
  78. }
  79. PerformanceManager::CallOnGraph(
  80. FROM_HERE,
  81. base::BindOnce(std::move(measure_memory_callback),
  82. PerformanceManager::GetFrameNodeForRenderFrameHost(rfh)));
  83. }
  84. } // anonymous namespace
  85. ////////////////////////////////////////////////////////////////////////////////
  86. // WebMemoryMeasurer
  87. WebMemoryMeasurer::WebMemoryMeasurer(
  88. const blink::LocalFrameToken& frame_token,
  89. V8DetailedMemoryRequest::MeasurementMode mode,
  90. MeasurementCallback callback)
  91. : frame_token_(frame_token),
  92. callback_(std::move(callback)),
  93. request_(std::make_unique<V8DetailedMemoryRequestOneShot>(mode)) {}
  94. WebMemoryMeasurer::~WebMemoryMeasurer() = default;
  95. // static
  96. void WebMemoryMeasurer::MeasureMemory(mojom::WebMemoryMeasurement::Mode mode,
  97. MeasurementCallback callback,
  98. base::WeakPtr<FrameNode> frame_node) {
  99. if (!frame_node) {
  100. // Frame was deleted while validating it on the UI sequence.
  101. return;
  102. }
  103. // Can't use make_unique with a private constructor.
  104. auto measurer = base::WrapUnique(new WebMemoryMeasurer(
  105. frame_node->GetFrameToken(),
  106. WebMeasurementModeToRequestMeasurementMode(mode), std::move(callback)));
  107. // Create a measurement complete callback to own |measurer|. It
  108. // will be deleted when the callback is executed or dropped.
  109. V8DetailedMemoryRequestOneShot* request = measurer->request();
  110. auto measurement_complete_callback = base::BindOnce(
  111. &WebMemoryMeasurer::MeasurementComplete, std::move(measurer));
  112. // Start memory measurement for the process of the given frame.
  113. request->StartMeasurement(frame_node->GetProcessNode(),
  114. std::move(measurement_complete_callback));
  115. }
  116. void WebMemoryMeasurer::MeasurementComplete(
  117. const ProcessNode* process_node,
  118. const V8DetailedMemoryProcessData*) {
  119. std::move(callback_).Run(BuildMemoryUsageResult(frame_token_, process_node));
  120. }
  121. ////////////////////////////////////////////////////////////////////////////////
  122. // WebMeasureMemorySecurityCheckerImpl
  123. // Implements the public function in public/v8_memory/web_memory.h
  124. std::unique_ptr<WebMeasureMemorySecurityChecker>
  125. WebMeasureMemorySecurityChecker::Create() {
  126. return std::make_unique<WebMeasureMemorySecurityCheckerImpl>();
  127. }
  128. void WebMeasureMemorySecurityCheckerImpl::CheckMeasureMemoryIsAllowed(
  129. const FrameNode* frame,
  130. MeasureMemoryCallback measure_memory_callback,
  131. mojo::ReportBadMessageCallback bad_message_callback) const {
  132. DCHECK(frame);
  133. DCHECK_ON_GRAPH_SEQUENCE(frame->GetGraph());
  134. // TODO(crbug/1085129): The frame may have navigated since it sent the
  135. // measureMemory request. We could return true if the new document is allowed
  136. // to measure memory, but the actual document that sent the request is not.
  137. // If that happens the DocumentCoordinationUnit mojo interface is reset so
  138. // the measurement result will be thrown away, so this is not a security
  139. // issue, but it does mean doing extra work.
  140. if (!base::FeatureList::IsEnabled(
  141. blink::features::kWebMeasureMemoryViaPerformanceManager)) {
  142. std::move(bad_message_callback)
  143. .Run("WebMeasureMemoryViaPerformanceManager feature is disabled");
  144. return;
  145. }
  146. content::GetUIThreadTaskRunner({})->PostTask(
  147. FROM_HERE, base::BindOnce(&CheckIsCrossOriginIsolatedOnUISeq,
  148. frame->GetRenderFrameHostProxy(),
  149. std::move(measure_memory_callback),
  150. std::move(bad_message_callback)));
  151. }
  152. ////////////////////////////////////////////////////////////////////////////////
  153. // Free functions
  154. // Implements the public function in public/v8_memory/web_memory.h
  155. void WebMeasureMemory(
  156. const FrameNode* frame_node,
  157. mojom::WebMemoryMeasurement::Mode mode,
  158. std::unique_ptr<WebMeasureMemorySecurityChecker> security_checker,
  159. base::OnceCallback<void(mojom::WebMemoryMeasurementPtr)> result_callback,
  160. mojo::ReportBadMessageCallback bad_message_callback) {
  161. DCHECK(frame_node);
  162. DCHECK(security_checker);
  163. // Validate that |frame_node| is allowed to measure memory, then start the
  164. // measurement.
  165. security_checker->CheckMeasureMemoryIsAllowed(
  166. frame_node,
  167. base::BindOnce(&WebMemoryMeasurer::MeasureMemory, mode,
  168. std::move(result_callback)),
  169. std::move(bad_message_callback));
  170. }
  171. } // namespace v8_memory
  172. } // namespace performance_manager