#include "content/web_test/browser/leak_detector.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_writer.h"
#include "base/values.h"
#include "content/public/browser/render_process_host.h"
namespace content {
const int kInitialNumberOfLiveAudioNodes = 0;
const int kInitialNumberOfLiveDocuments = 1;
const int kInitialNumberOfLiveNodes = 4;
const int kInitialNumberOfLiveLayoutObjects = 3;
const int kInitialNumberOfLiveResources = 0;
const int kInitialNumberOfLiveFrames = 1;
const int kInitialNumberOfWorkerGlobalScopes = 0;
const int kInitialNumberOfLiveResourceFetchers = 1;
const int kInitialNumberOfLiveContextLifecycleStateObservers = 2;
const int kInitialNumberOfV8PerContextData = 2;
LeakDetector::LeakDetector() {
previous_result_ = blink::mojom::LeakDetectionResult::New();
previous_result_->number_of_live_audio_nodes = kInitialNumberOfLiveAudioNodes;
previous_result_->number_of_live_documents = kInitialNumberOfLiveDocuments;
previous_result_->number_of_live_nodes = kInitialNumberOfLiveNodes;
previous_result_->number_of_live_layout_objects =
kInitialNumberOfLiveLayoutObjects;
previous_result_->number_of_live_resources = kInitialNumberOfLiveResources;
previous_result_->number_of_live_context_lifecycle_state_observers =
kInitialNumberOfLiveContextLifecycleStateObservers;
previous_result_->number_of_live_frames = kInitialNumberOfLiveFrames;
previous_result_->number_of_live_v8_per_context_data =
kInitialNumberOfV8PerContextData;
previous_result_->number_of_worker_global_scopes =
kInitialNumberOfWorkerGlobalScopes;
previous_result_->number_of_live_resource_fetchers =
kInitialNumberOfLiveResourceFetchers;
}
LeakDetector::~LeakDetector() {}
void LeakDetector::TryLeakDetection(RenderProcessHost* process,
ReportCallback callback) {
callback_ = std::move(callback);
if (!leak_detector_) {
process->BindReceiver(leak_detector_.BindNewPipeAndPassReceiver());
leak_detector_.set_disconnect_handler(base::BindOnce(
&LeakDetector::OnLeakDetectorIsGone, base::Unretained(this)));
}
leak_detector_->PerformLeakDetection(base::BindOnce(
&LeakDetector::OnLeakDetectionComplete, weak_factory_.GetWeakPtr()));
}
void LeakDetector::OnLeakDetectionComplete(
blink::mojom::LeakDetectionResultPtr result) {
LeakDetectionReport report;
report.leaked = false;
base::Value::Dict detail;
if (previous_result_ && !result.is_null()) {
if (previous_result_->number_of_live_audio_nodes <
result->number_of_live_audio_nodes) {
base::Value::List list;
list.Append(
static_cast<int>(previous_result_->number_of_live_audio_nodes));
list.Append(static_cast<int>(result->number_of_live_audio_nodes));
detail.Set("numberOfLiveAudioNodes", std::move(list));
}
if (previous_result_->number_of_live_documents <
result->number_of_live_documents) {
base::Value::List list;
list.Append(static_cast<int>(previous_result_->number_of_live_documents));
list.Append(static_cast<int>(result->number_of_live_documents));
detail.Set("numberOfLiveDocuments", std::move(list));
}
if (previous_result_->number_of_live_nodes < result->number_of_live_nodes) {
base::Value::List list;
list.Append(static_cast<int>(previous_result_->number_of_live_nodes));
list.Append(static_cast<int>(result->number_of_live_nodes));
detail.Set("numberOfLiveNodes", std::move(list));
}
if (previous_result_->number_of_live_layout_objects <
result->number_of_live_layout_objects) {
base::Value::List list;
list.Append(
static_cast<int>(previous_result_->number_of_live_layout_objects));
list.Append(static_cast<int>(result->number_of_live_layout_objects));
detail.Set("numberOfLiveLayoutObjects", std::move(list));
}
if (previous_result_->number_of_live_resources <
(result->number_of_live_resources -
result->number_of_live_ua_css_resources)) {
base::Value::List list;
list.Append(static_cast<int>(previous_result_->number_of_live_resources));
list.Append(static_cast<int>(result->number_of_live_resources));
detail.Set("numberOfLiveResources", std::move(list));
}
if (previous_result_->number_of_live_context_lifecycle_state_observers <
result->number_of_live_context_lifecycle_state_observers) {
base::Value::List list;
list.Append(static_cast<int>(
previous_result_->number_of_live_context_lifecycle_state_observers));
list.Append(static_cast<int>(
result->number_of_live_context_lifecycle_state_observers));
detail.Set("numberOfLiveContextLifecycleStateObservers", std::move(list));
}
if (previous_result_->number_of_live_frames <
result->number_of_live_frames) {
base::Value::List list;
list.Append(static_cast<int>(previous_result_->number_of_live_frames));
list.Append(static_cast<int>(result->number_of_live_frames));
detail.Set("numberOfLiveFrames", std::move(list));
}
if (previous_result_->number_of_live_v8_per_context_data <
result->number_of_live_v8_per_context_data) {
base::Value::List list;
list.Append(static_cast<int>(
previous_result_->number_of_live_v8_per_context_data));
list.Append(static_cast<int>(result->number_of_live_v8_per_context_data));
detail.Set("numberOfLiveV8PerContextData", std::move(list));
}
if (previous_result_->number_of_worker_global_scopes <
result->number_of_worker_global_scopes) {
base::Value::List list;
list.Append(
static_cast<int>(previous_result_->number_of_worker_global_scopes));
list.Append(static_cast<int>(result->number_of_worker_global_scopes));
detail.Set("numberOfWorkerGlobalScopes", std::move(list));
}
if (previous_result_->number_of_live_resource_fetchers <
result->number_of_live_resource_fetchers) {
base::Value::List list;
list.Append(
static_cast<int>(previous_result_->number_of_live_resource_fetchers));
list.Append(static_cast<int>(result->number_of_live_resource_fetchers));
detail.Set("numberOfLiveResourceFetchers", std::move(list));
}
}
if (!detail.empty()) {
report.detail = base::WriteJson(detail).value_or("");
report.leaked = true;
}
if (!result.is_null()) {
previous_result_ = std::move(result);
}
std::move(callback_).Run(report);
}
void LeakDetector::OnLeakDetectorIsGone() {
leak_detector_.reset();
if (!callback_)
return;
LeakDetectionReport report;
report.leaked = false;
std::move(callback_).Run(report);
}
}