#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_libc_calls
#endif
#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>
#include <memoryapi.h>
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
#include <sys/mman.h>
#endif
#if BUILDFLAG(IS_ARKWEB)
#include <sys/prctl.h>
#endif
namespace {
constexpr size_t kAllocSize = 1 << 20;
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)
address = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED,
-1, 0);
if (address != MAP_FAILED) {
#if BUILDFLAG(IS_ARKWEB)
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, address, size, "web_metrics_histogram");
#endif
return address;
}
#else
#error This architecture is not (yet) supported.
#endif
if (!base::UncheckedMalloc(size, &address)) {
return nullptr;
}
DCHECK(address);
memset(address, 0, size);
return address;
}
}
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));
void* memory = AllocateLocalMemory(kAllocSize);
if (!memory) {
return;
}
GlobalHistogramAllocator::CreateWithPersistentMemory(memory, kAllocSize, 0,
0,
allocator_name);
GlobalHistogramAllocator::Get()->CreateTrackingHistograms(allocator_name);
}
PersistentHistogramStorage::~PersistentHistogramStorage() {
PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
if (!allocator) {
return;
}
allocator->UpdateTrackingHistograms();
if (disabled_) {
return;
}
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)) {
LOG(ERROR)
<< "Could not write \"" << allocator->Name()
<< "\" persistent histograms to file as the storage directory "
"does not exist.";
return;
}
break;
}
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();
}
}
}