chromium/third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.h"

#include <utility>

#include "base/metrics/histogram_macros.h"
#include "base/process/memory.h"
#include "partition_alloc/oom_callback.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"

namespace blink {

// static
void CrashMemoryMetricsReporterImpl::Bind(
    mojo::PendingReceiver<mojom::blink::CrashMemoryMetricsReporter> receiver) {
  // This should be called only once per process on RenderProcessWillLaunch.
  DCHECK(!CrashMemoryMetricsReporterImpl::Instance().receiver_.is_bound());
  CrashMemoryMetricsReporterImpl::Instance().receiver_.Bind(
      std::move(receiver));
}

CrashMemoryMetricsReporterImpl& CrashMemoryMetricsReporterImpl::Instance() {
  DEFINE_STATIC_LOCAL(CrashMemoryMetricsReporterImpl,
                      crash_memory_metrics_reporter_impl, ());
  return crash_memory_metrics_reporter_impl;
}

CrashMemoryMetricsReporterImpl::CrashMemoryMetricsReporterImpl() {
  ::partition_alloc::SetPartitionAllocOomCallback(
      CrashMemoryMetricsReporterImpl::OnOOMCallback);
}

CrashMemoryMetricsReporterImpl::~CrashMemoryMetricsReporterImpl() {
  MemoryUsageMonitor::Instance().RemoveObserver(this);
}

void CrashMemoryMetricsReporterImpl::SetSharedMemory(
    base::UnsafeSharedMemoryRegion shared_metrics_buffer) {
  // This method should be called only once per process.
  DCHECK(!shared_metrics_mapping_.IsValid());
  shared_metrics_mapping_ = shared_metrics_buffer.Map();
  MemoryUsageMonitor::Instance().AddObserver(this);
}

void CrashMemoryMetricsReporterImpl::OnMemoryPing(MemoryUsage usage) {
  DCHECK(IsMainThread());
  last_reported_metrics_ =
      CrashMemoryMetricsReporterImpl::MemoryUsageToMetrics(usage);
  WriteIntoSharedMemory();
}

void CrashMemoryMetricsReporterImpl::WriteIntoSharedMemory() {
  if (!shared_metrics_mapping_.IsValid())
    return;
  auto* metrics_shared =
      shared_metrics_mapping_.GetMemoryAs<OomInterventionMetrics>();
  *metrics_shared = last_reported_metrics_;
}

void CrashMemoryMetricsReporterImpl::OnOOMCallback() {
  // TODO(yuzus: Support allocation failures on other threads as well.
  if (!IsMainThread())
    return;
  CrashMemoryMetricsReporterImpl& instance =
      CrashMemoryMetricsReporterImpl::Instance();
  // If shared_metrics_mapping_ is not set, it means OnNoMemory happened before
  // initializing render process host sets the shared memory.
  if (!instance.shared_metrics_mapping_.IsValid())
    return;
  // Else, we can send the allocation_failed bool.
  // TODO(yuzus): Report this UMA on all the platforms. Currently this is only
  // reported on Android.
  instance.last_reported_metrics_.allocation_failed = 1;  // true
  instance.WriteIntoSharedMemory();
}

// static
OomInterventionMetrics CrashMemoryMetricsReporterImpl::MemoryUsageToMetrics(
    MemoryUsage usage) {
  OomInterventionMetrics metrics;

  DCHECK(!std::isnan(usage.private_footprint_bytes));
  DCHECK(!std::isnan(usage.swap_bytes));
  DCHECK(!std::isnan(usage.vm_size_bytes));
  metrics.current_blink_usage_kb =
      (usage.v8_bytes + usage.blink_gc_bytes + usage.partition_alloc_bytes) /
      1024;

  DCHECK(!std::isnan(usage.private_footprint_bytes));
  DCHECK(!std::isnan(usage.swap_bytes));
  DCHECK(!std::isnan(usage.vm_size_bytes));
  metrics.current_private_footprint_kb = usage.private_footprint_bytes / 1024;
  metrics.current_swap_kb = usage.swap_bytes / 1024;
  metrics.current_vm_size_kb = usage.vm_size_bytes / 1024;
  metrics.allocation_failed = 0;  // false
  return metrics;
}

}  // namespace blink