mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-25 06:46:09 +03:00
152 lines
5.0 KiB
C++
152 lines
5.0 KiB
C++
|
// 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 "base/metrics/persistent_histogram_storage.h"
|
||
|
|
||
|
#include <cinttypes>
|
||
|
#include <string_view>
|
||
|
|
||
|
#include "base/files/file_util.h"
|
||
|
#include "base/files/important_file_writer.h"
|
||
|
#include "base/logging.h"
|
||
|
#include "base/metrics/persistent_histogram_allocator.h"
|
||
|
#include "base/metrics/persistent_memory_allocator.h"
|
||
|
#include "base/process/memory.h"
|
||
|
#include "base/strings/string_util.h"
|
||
|
#include "base/strings/stringprintf.h"
|
||
|
#include "base/time/time.h"
|
||
|
#include "build/build_config.h"
|
||
|
|
||
|
#if BUILDFLAG(IS_WIN)
|
||
|
#include <windows.h>
|
||
|
// Must be after <windows.h>
|
||
|
#include <memoryapi.h>
|
||
|
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
|
||
|
#include <sys/mman.h>
|
||
|
#endif
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
constexpr size_t kAllocSize = 1 << 20; // 1 MiB
|
||
|
|
||
|
void* AllocateLocalMemory(size_t size) {
|
||
|
void* address;
|
||
|
|
||
|
#if BUILDFLAG(IS_WIN)
|
||
|
address =
|
||
|
::VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||
|
if (address)
|
||
|
return address;
|
||
|
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
|
||
|
// MAP_ANON is deprecated on Linux but MAP_ANONYMOUS is not universal on Mac.
|
||
|
// MAP_SHARED is not available on Linux <2.4 but required on Mac.
|
||
|
address = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED,
|
||
|
-1, 0);
|
||
|
if (address != MAP_FAILED)
|
||
|
return address;
|
||
|
#else
|
||
|
#error This architecture is not (yet) supported.
|
||
|
#endif
|
||
|
|
||
|
// As a last resort, just allocate the memory from the heap. This will
|
||
|
// achieve the same basic result but the acquired memory has to be
|
||
|
// explicitly zeroed and thus realized immediately (i.e. all pages are
|
||
|
// added to the process now instead of only when first accessed).
|
||
|
if (!base::UncheckedMalloc(size, &address))
|
||
|
return nullptr;
|
||
|
DCHECK(address);
|
||
|
memset(address, 0, size);
|
||
|
return address;
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
namespace base {
|
||
|
|
||
|
PersistentHistogramStorage::PersistentHistogramStorage(
|
||
|
std::string_view allocator_name,
|
||
|
StorageDirManagement storage_dir_management)
|
||
|
: storage_dir_management_(storage_dir_management) {
|
||
|
DCHECK(!allocator_name.empty());
|
||
|
DCHECK(IsStringASCII(allocator_name));
|
||
|
|
||
|
// This code may be executed before crash handling and/or OOM handling has
|
||
|
// been initialized for the process. Silently ignore a failed allocation
|
||
|
// (no metric persistence) rather that generating a crash that won't be
|
||
|
// caught/reported.
|
||
|
void* memory = AllocateLocalMemory(kAllocSize);
|
||
|
if (!memory)
|
||
|
return;
|
||
|
|
||
|
GlobalHistogramAllocator::CreateWithPersistentMemory(memory, kAllocSize, 0,
|
||
|
0, // No identifier.
|
||
|
allocator_name);
|
||
|
GlobalHistogramAllocator::Get()->CreateTrackingHistograms(allocator_name);
|
||
|
}
|
||
|
|
||
|
PersistentHistogramStorage::~PersistentHistogramStorage() {
|
||
|
PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
|
||
|
if (!allocator)
|
||
|
return;
|
||
|
|
||
|
allocator->UpdateTrackingHistograms();
|
||
|
|
||
|
if (disabled_)
|
||
|
return;
|
||
|
|
||
|
// Stop if the storage base directory has not been properly set.
|
||
|
if (storage_base_dir_.empty()) {
|
||
|
LOG(ERROR)
|
||
|
<< "Could not write \"" << allocator->Name()
|
||
|
<< "\" persistent histograms to file as the storage base directory "
|
||
|
"is not properly set.";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
FilePath storage_dir = storage_base_dir_.AppendASCII(allocator->Name());
|
||
|
|
||
|
switch (storage_dir_management_) {
|
||
|
case StorageDirManagement::kCreate:
|
||
|
if (!CreateDirectory(storage_dir)) {
|
||
|
LOG(ERROR)
|
||
|
<< "Could not write \"" << allocator->Name()
|
||
|
<< "\" persistent histograms to file as the storage directory "
|
||
|
"cannot be created.";
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case StorageDirManagement::kUseExisting:
|
||
|
if (!DirectoryExists(storage_dir)) {
|
||
|
// When the consumer of this class decides to use an existing storage
|
||
|
// directory, it should ensure the directory's existence if it's
|
||
|
// essential.
|
||
|
LOG(ERROR)
|
||
|
<< "Could not write \"" << allocator->Name()
|
||
|
<< "\" persistent histograms to file as the storage directory "
|
||
|
"does not exist.";
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Save data using the process ID and microseconds since Windows Epoch for the
|
||
|
// filename with the correct extension. Using this format prevents collisions
|
||
|
// between multiple processes using the same provider name.
|
||
|
const FilePath file_path =
|
||
|
storage_dir
|
||
|
.AppendASCII(StringPrintf(
|
||
|
"%" CrPRIdPid "_%" PRId64, GetCurrentProcId(),
|
||
|
Time::Now().ToDeltaSinceWindowsEpoch().InMicroseconds()))
|
||
|
.AddExtension(PersistentMemoryAllocator::kFileExtension);
|
||
|
|
||
|
std::string_view contents(static_cast<const char*>(allocator->data()),
|
||
|
allocator->used());
|
||
|
if (!ImportantFileWriter::WriteFileAtomically(file_path, contents)) {
|
||
|
LOG(ERROR) << "Persistent histograms fail to write to file: "
|
||
|
<< file_path.value();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace base
|