Home | History | Annotate | Download | only in metrics
      1 // Copyright 2016 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 
      5 #include "base/metrics/persistent_histogram_allocator.h"
      6 
      7 #include <memory>
      8 
      9 #include "base/atomicops.h"
     10 #include "base/files/file_path.h"
     11 #include "base/files/file_util.h"
     12 #include "base/files/important_file_writer.h"
     13 #include "base/files/memory_mapped_file.h"
     14 #include "base/lazy_instance.h"
     15 #include "base/logging.h"
     16 #include "base/memory/ptr_util.h"
     17 #include "base/metrics/histogram.h"
     18 #include "base/metrics/histogram_base.h"
     19 #include "base/metrics/histogram_samples.h"
     20 #include "base/metrics/metrics_hashes.h"
     21 #include "base/metrics/persistent_sample_map.h"
     22 #include "base/metrics/sparse_histogram.h"
     23 #include "base/metrics/statistics_recorder.h"
     24 #include "base/numerics/safe_conversions.h"
     25 #include "base/pickle.h"
     26 #include "base/process/process_handle.h"
     27 #include "base/strings/string_number_conversions.h"
     28 #include "base/strings/string_split.h"
     29 #include "base/strings/stringprintf.h"
     30 #include "base/synchronization/lock.h"
     31 
     32 namespace base {
     33 
     34 namespace {
     35 
     36 // Type identifiers used when storing in persistent memory so they can be
     37 // identified during extraction; the first 4 bytes of the SHA1 of the name
     38 // is used as a unique integer. A "version number" is added to the base
     39 // so that, if the structure of that object changes, stored older versions
     40 // will be safely ignored.
     41 enum : uint32_t {
     42   kTypeIdRangesArray = 0xBCEA225A + 1,  // SHA1(RangesArray) v1
     43   kTypeIdCountsArray = 0x53215530 + 1,  // SHA1(CountsArray) v1
     44 };
     45 
     46 // The current globally-active persistent allocator for all new histograms.
     47 // The object held here will obviously not be destructed at process exit
     48 // but that's best since PersistentMemoryAllocator objects (that underlie
     49 // GlobalHistogramAllocator objects) are explicitly forbidden from doing
     50 // anything essential at exit anyway due to the fact that they depend on data
     51 // managed elsewhere and which could be destructed first. An AtomicWord is
     52 // used instead of std::atomic because the latter can create global ctors
     53 // and dtors.
     54 subtle::AtomicWord g_histogram_allocator = 0;
     55 
     56 // Take an array of range boundaries and create a proper BucketRanges object
     57 // which is returned to the caller. A return of nullptr indicates that the
     58 // passed boundaries are invalid.
     59 std::unique_ptr<BucketRanges> CreateRangesFromData(
     60     HistogramBase::Sample* ranges_data,
     61     uint32_t ranges_checksum,
     62     size_t count) {
     63   // To avoid racy destruction at shutdown, the following may be leaked.
     64   std::unique_ptr<BucketRanges> ranges(new BucketRanges(count));
     65   DCHECK_EQ(count, ranges->size());
     66   for (size_t i = 0; i < count; ++i) {
     67     if (i > 0 && ranges_data[i] <= ranges_data[i - 1])
     68       return nullptr;
     69     ranges->set_range(i, ranges_data[i]);
     70   }
     71 
     72   ranges->ResetChecksum();
     73   if (ranges->checksum() != ranges_checksum)
     74     return nullptr;
     75 
     76   return ranges;
     77 }
     78 
     79 // Calculate the number of bytes required to store all of a histogram's
     80 // "counts". This will return zero (0) if |bucket_count| is not valid.
     81 size_t CalculateRequiredCountsBytes(size_t bucket_count) {
     82   // 2 because each "sample count" also requires a backup "logged count"
     83   // used for calculating the delta during snapshot operations.
     84   const size_t kBytesPerBucket = 2 * sizeof(HistogramBase::AtomicCount);
     85 
     86   // If the |bucket_count| is such that it would overflow the return type,
     87   // perhaps as the result of a malicious actor, then return zero to
     88   // indicate the problem to the caller.
     89   if (bucket_count > std::numeric_limits<size_t>::max() / kBytesPerBucket)
     90     return 0;
     91 
     92   return bucket_count * kBytesPerBucket;
     93 }
     94 
     95 }  // namespace
     96 
     97 const Feature kPersistentHistogramsFeature{
     98   "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT
     99 };
    100 
    101 
    102 PersistentSparseHistogramDataManager::PersistentSparseHistogramDataManager(
    103     PersistentMemoryAllocator* allocator)
    104     : allocator_(allocator), record_iterator_(allocator) {}
    105 
    106 PersistentSparseHistogramDataManager::~PersistentSparseHistogramDataManager() =
    107     default;
    108 
    109 PersistentSampleMapRecords*
    110 PersistentSparseHistogramDataManager::UseSampleMapRecords(uint64_t id,
    111                                                           const void* user) {
    112   base::AutoLock auto_lock(lock_);
    113   return GetSampleMapRecordsWhileLocked(id)->Acquire(user);
    114 }
    115 
    116 PersistentSampleMapRecords*
    117 PersistentSparseHistogramDataManager::GetSampleMapRecordsWhileLocked(
    118     uint64_t id) {
    119   lock_.AssertAcquired();
    120 
    121   auto found = sample_records_.find(id);
    122   if (found != sample_records_.end())
    123     return found->second.get();
    124 
    125   std::unique_ptr<PersistentSampleMapRecords>& samples = sample_records_[id];
    126   samples = std::make_unique<PersistentSampleMapRecords>(this, id);
    127   return samples.get();
    128 }
    129 
    130 bool PersistentSparseHistogramDataManager::LoadRecords(
    131     PersistentSampleMapRecords* sample_map_records) {
    132   // DataManager must be locked in order to access the found_ field of any
    133   // PersistentSampleMapRecords object.
    134   base::AutoLock auto_lock(lock_);
    135   bool found = false;
    136 
    137   // If there are already "found" entries for the passed object, move them.
    138   if (!sample_map_records->found_.empty()) {
    139     sample_map_records->records_.reserve(sample_map_records->records_.size() +
    140                                          sample_map_records->found_.size());
    141     sample_map_records->records_.insert(sample_map_records->records_.end(),
    142                                         sample_map_records->found_.begin(),
    143                                         sample_map_records->found_.end());
    144     sample_map_records->found_.clear();
    145     found = true;
    146   }
    147 
    148   // Acquiring a lock is a semi-expensive operation so load some records with
    149   // each call. More than this number may be loaded if it takes longer to
    150   // find at least one matching record for the passed object.
    151   const int kMinimumNumberToLoad = 10;
    152   const uint64_t match_id = sample_map_records->sample_map_id_;
    153 
    154   // Loop while no enty is found OR we haven't yet loaded the minimum number.
    155   // This will continue reading even after a match is found.
    156   for (int count = 0; !found || count < kMinimumNumberToLoad; ++count) {
    157     // Get the next sample-record. The iterator will always resume from where
    158     // it left off even if it previously had nothing further to return.
    159     uint64_t found_id;
    160     PersistentMemoryAllocator::Reference ref =
    161         PersistentSampleMap::GetNextPersistentRecord(record_iterator_,
    162                                                      &found_id);
    163 
    164     // Stop immediately if there are none.
    165     if (!ref)
    166       break;
    167 
    168     // The sample-record could be for any sparse histogram. Add the reference
    169     // to the appropriate collection for later use.
    170     if (found_id == match_id) {
    171       sample_map_records->records_.push_back(ref);
    172       found = true;
    173     } else {
    174       PersistentSampleMapRecords* samples =
    175           GetSampleMapRecordsWhileLocked(found_id);
    176       DCHECK(samples);
    177       samples->found_.push_back(ref);
    178     }
    179   }
    180 
    181   return found;
    182 }
    183 
    184 
    185 PersistentSampleMapRecords::PersistentSampleMapRecords(
    186     PersistentSparseHistogramDataManager* data_manager,
    187     uint64_t sample_map_id)
    188     : data_manager_(data_manager), sample_map_id_(sample_map_id) {}
    189 
    190 PersistentSampleMapRecords::~PersistentSampleMapRecords() = default;
    191 
    192 PersistentSampleMapRecords* PersistentSampleMapRecords::Acquire(
    193     const void* user) {
    194   DCHECK(!user_);
    195   user_ = user;
    196   seen_ = 0;
    197   return this;
    198 }
    199 
    200 void PersistentSampleMapRecords::Release(const void* user) {
    201   DCHECK_EQ(user_, user);
    202   user_ = nullptr;
    203 }
    204 
    205 PersistentMemoryAllocator::Reference PersistentSampleMapRecords::GetNext() {
    206   DCHECK(user_);
    207 
    208   // If there are no unseen records, lock and swap in all the found ones.
    209   if (records_.size() == seen_) {
    210     if (!data_manager_->LoadRecords(this))
    211       return false;
    212   }
    213 
    214   // Return the next record. Records *must* be returned in the same order
    215   // they are found in the persistent memory in order to ensure that all
    216   // objects using this data always have the same state. Race conditions
    217   // can cause duplicate records so using the "first found" is the only
    218   // guarantee that all objects always access the same one.
    219   DCHECK_LT(seen_, records_.size());
    220   return records_[seen_++];
    221 }
    222 
    223 PersistentMemoryAllocator::Reference PersistentSampleMapRecords::CreateNew(
    224     HistogramBase::Sample value) {
    225   return PersistentSampleMap::CreatePersistentRecord(data_manager_->allocator_,
    226                                                      sample_map_id_, value);
    227 }
    228 
    229 
    230 // This data will be held in persistent memory in order for processes to
    231 // locate and use histograms created elsewhere.
    232 struct PersistentHistogramAllocator::PersistentHistogramData {
    233   // SHA1(Histogram): Increment this if structure changes!
    234   static constexpr uint32_t kPersistentTypeId = 0xF1645910 + 3;
    235 
    236   // Expected size for 32/64-bit check.
    237   static constexpr size_t kExpectedInstanceSize =
    238       40 + 2 * HistogramSamples::Metadata::kExpectedInstanceSize;
    239 
    240   int32_t histogram_type;
    241   int32_t flags;
    242   int32_t minimum;
    243   int32_t maximum;
    244   uint32_t bucket_count;
    245   PersistentMemoryAllocator::Reference ranges_ref;
    246   uint32_t ranges_checksum;
    247   subtle::Atomic32 counts_ref;  // PersistentMemoryAllocator::Reference
    248   HistogramSamples::Metadata samples_metadata;
    249   HistogramSamples::Metadata logged_metadata;
    250 
    251   // Space for the histogram name will be added during the actual allocation
    252   // request. This must be the last field of the structure. A zero-size array
    253   // or a "flexible" array would be preferred but is not (yet) valid C++.
    254   char name[sizeof(uint64_t)];  // Force 64-bit alignment on 32-bit builds.
    255 };
    256 
    257 PersistentHistogramAllocator::Iterator::Iterator(
    258     PersistentHistogramAllocator* allocator)
    259     : allocator_(allocator), memory_iter_(allocator->memory_allocator()) {}
    260 
    261 std::unique_ptr<HistogramBase>
    262 PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) {
    263   PersistentMemoryAllocator::Reference ref;
    264   while ((ref = memory_iter_.GetNextOfType<PersistentHistogramData>()) != 0) {
    265     if (ref != ignore)
    266       return allocator_->GetHistogram(ref);
    267   }
    268   return nullptr;
    269 }
    270 
    271 
    272 PersistentHistogramAllocator::PersistentHistogramAllocator(
    273     std::unique_ptr<PersistentMemoryAllocator> memory)
    274     : memory_allocator_(std::move(memory)),
    275       sparse_histogram_data_manager_(memory_allocator_.get()) {}
    276 
    277 PersistentHistogramAllocator::~PersistentHistogramAllocator() = default;
    278 
    279 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::GetHistogram(
    280     Reference ref) {
    281   // Unfortunately, the histogram "pickle" methods cannot be used as part of
    282   // the persistance because the deserialization methods always create local
    283   // count data (while these must reference the persistent counts) and always
    284   // add it to the local list of known histograms (while these may be simple
    285   // references to histograms in other processes).
    286   PersistentHistogramData* data =
    287       memory_allocator_->GetAsObject<PersistentHistogramData>(ref);
    288   const size_t length = memory_allocator_->GetAllocSize(ref);
    289 
    290   // Check that metadata is reasonable: name is null-terminated and non-empty,
    291   // ID fields have been loaded with a hash of the name (0 is considered
    292   // unset/invalid).
    293   if (!data || data->name[0] == '\0' ||
    294       reinterpret_cast<char*>(data)[length - 1] != '\0' ||
    295       data->samples_metadata.id == 0 || data->logged_metadata.id == 0 ||
    296       // Note: Sparse histograms use |id + 1| in |logged_metadata|.
    297       (data->logged_metadata.id != data->samples_metadata.id &&
    298        data->logged_metadata.id != data->samples_metadata.id + 1) ||
    299       // Most non-matching values happen due to truncated names. Ideally, we
    300       // could just verify the name length based on the overall alloc length,
    301       // but that doesn't work because the allocated block may have been
    302       // aligned to the next boundary value.
    303       HashMetricName(data->name) != data->samples_metadata.id) {
    304     return nullptr;
    305   }
    306   return CreateHistogram(data);
    307 }
    308 
    309 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
    310     HistogramType histogram_type,
    311     const std::string& name,
    312     int minimum,
    313     int maximum,
    314     const BucketRanges* bucket_ranges,
    315     int32_t flags,
    316     Reference* ref_ptr) {
    317   // If the allocator is corrupt, don't waste time trying anything else.
    318   // This also allows differentiating on the dashboard between allocations
    319   // failed due to a corrupt allocator and the number of process instances
    320   // with one, the latter being idicated by "newly corrupt", below.
    321   if (memory_allocator_->IsCorrupt())
    322     return nullptr;
    323 
    324   // Create the metadata necessary for a persistent sparse histogram. This
    325   // is done first because it is a small subset of what is required for
    326   // other histograms. The type is "under construction" so that a crash
    327   // during the datafill doesn't leave a bad record around that could cause
    328   // confusion by another process trying to read it. It will be corrected
    329   // once histogram construction is complete.
    330   PersistentHistogramData* histogram_data =
    331       memory_allocator_->New<PersistentHistogramData>(
    332           offsetof(PersistentHistogramData, name) + name.length() + 1);
    333   if (histogram_data) {
    334     memcpy(histogram_data->name, name.c_str(), name.size() + 1);
    335     histogram_data->histogram_type = histogram_type;
    336     histogram_data->flags = flags | HistogramBase::kIsPersistent;
    337   }
    338 
    339   // Create the remaining metadata necessary for regular histograms.
    340   if (histogram_type != SPARSE_HISTOGRAM) {
    341     size_t bucket_count = bucket_ranges->bucket_count();
    342     size_t counts_bytes = CalculateRequiredCountsBytes(bucket_count);
    343     if (counts_bytes == 0) {
    344       // |bucket_count| was out-of-range.
    345       return nullptr;
    346     }
    347 
    348     // Since the StasticsRecorder keeps a global collection of BucketRanges
    349     // objects for re-use, it would be dangerous for one to hold a reference
    350     // from a persistent allocator that is not the global one (which is
    351     // permanent once set). If this stops being the case, this check can
    352     // become an "if" condition beside "!ranges_ref" below and before
    353     // set_persistent_reference() farther down.
    354     DCHECK_EQ(this, GlobalHistogramAllocator::Get());
    355 
    356     // Re-use an existing BucketRanges persistent allocation if one is known;
    357     // otherwise, create one.
    358     PersistentMemoryAllocator::Reference ranges_ref =
    359         bucket_ranges->persistent_reference();
    360     if (!ranges_ref) {
    361       size_t ranges_count = bucket_count + 1;
    362       size_t ranges_bytes = ranges_count * sizeof(HistogramBase::Sample);
    363       ranges_ref =
    364           memory_allocator_->Allocate(ranges_bytes, kTypeIdRangesArray);
    365       if (ranges_ref) {
    366         HistogramBase::Sample* ranges_data =
    367             memory_allocator_->GetAsArray<HistogramBase::Sample>(
    368                 ranges_ref, kTypeIdRangesArray, ranges_count);
    369         if (ranges_data) {
    370           for (size_t i = 0; i < bucket_ranges->size(); ++i)
    371             ranges_data[i] = bucket_ranges->range(i);
    372           bucket_ranges->set_persistent_reference(ranges_ref);
    373         } else {
    374           // This should never happen but be tolerant if it does.
    375           ranges_ref = PersistentMemoryAllocator::kReferenceNull;
    376         }
    377       }
    378     } else {
    379       DCHECK_EQ(kTypeIdRangesArray, memory_allocator_->GetType(ranges_ref));
    380     }
    381 
    382 
    383     // Only continue here if all allocations were successful. If they weren't,
    384     // there is no way to free the space but that's not really a problem since
    385     // the allocations only fail because the space is full or corrupt and so
    386     // any future attempts will also fail.
    387     if (ranges_ref && histogram_data) {
    388       histogram_data->minimum = minimum;
    389       histogram_data->maximum = maximum;
    390       // |bucket_count| must fit within 32-bits or the allocation of the counts
    391       // array would have failed for being too large; the allocator supports
    392       // less than 4GB total size.
    393       histogram_data->bucket_count = static_cast<uint32_t>(bucket_count);
    394       histogram_data->ranges_ref = ranges_ref;
    395       histogram_data->ranges_checksum = bucket_ranges->checksum();
    396     } else {
    397       histogram_data = nullptr;  // Clear this for proper handling below.
    398     }
    399   }
    400 
    401   if (histogram_data) {
    402     // Create the histogram using resources in persistent memory. This ends up
    403     // resolving the "ref" values stored in histogram_data instad of just
    404     // using what is already known above but avoids duplicating the switch
    405     // statement here and serves as a double-check that everything is
    406     // correct before commiting the new histogram to persistent space.
    407     std::unique_ptr<HistogramBase> histogram = CreateHistogram(histogram_data);
    408     DCHECK(histogram);
    409     DCHECK_NE(0U, histogram_data->samples_metadata.id);
    410     DCHECK_NE(0U, histogram_data->logged_metadata.id);
    411 
    412     PersistentMemoryAllocator::Reference histogram_ref =
    413         memory_allocator_->GetAsReference(histogram_data);
    414     if (ref_ptr != nullptr)
    415       *ref_ptr = histogram_ref;
    416 
    417     // By storing the reference within the allocator to this histogram, the
    418     // next import (which will happen before the next histogram creation)
    419     // will know to skip it.
    420     // See also the comment in ImportHistogramsToStatisticsRecorder().
    421     subtle::NoBarrier_Store(&last_created_, histogram_ref);
    422     return histogram;
    423   }
    424 
    425   return nullptr;
    426 }
    427 
    428 void PersistentHistogramAllocator::FinalizeHistogram(Reference ref,
    429                                                      bool registered) {
    430   if (registered) {
    431     // If the created persistent histogram was registered then it needs to
    432     // be marked as "iterable" in order to be found by other processes. This
    433     // happens only after the histogram is fully formed so it's impossible for
    434     // code iterating through the allocator to read a partially created record.
    435     memory_allocator_->MakeIterable(ref);
    436   } else {
    437     // If it wasn't registered then a race condition must have caused two to
    438     // be created. The allocator does not support releasing the acquired memory
    439     // so just change the type to be empty.
    440     memory_allocator_->ChangeType(ref, 0,
    441                                   PersistentHistogramData::kPersistentTypeId,
    442                                   /*clear=*/false);
    443   }
    444 }
    445 
    446 void PersistentHistogramAllocator::MergeHistogramDeltaToStatisticsRecorder(
    447     HistogramBase* histogram) {
    448   DCHECK(histogram);
    449 
    450   HistogramBase* existing = GetOrCreateStatisticsRecorderHistogram(histogram);
    451   if (!existing) {
    452     // The above should never fail but if it does, no real harm is done.
    453     // The data won't be merged but it also won't be recorded as merged
    454     // so a future try, if successful, will get what was missed. If it
    455     // continues to fail, some metric data will be lost but that is better
    456     // than crashing.
    457     return;
    458   }
    459 
    460   // Merge the delta from the passed object to the one in the SR.
    461   existing->AddSamples(*histogram->SnapshotDelta());
    462 }
    463 
    464 void PersistentHistogramAllocator::MergeHistogramFinalDeltaToStatisticsRecorder(
    465     const HistogramBase* histogram) {
    466   DCHECK(histogram);
    467 
    468   HistogramBase* existing = GetOrCreateStatisticsRecorderHistogram(histogram);
    469   if (!existing) {
    470     // The above should never fail but if it does, no real harm is done.
    471     // Some metric data will be lost but that is better than crashing.
    472     return;
    473   }
    474 
    475   // Merge the delta from the passed object to the one in the SR.
    476   existing->AddSamples(*histogram->SnapshotFinalDelta());
    477 }
    478 
    479 PersistentSampleMapRecords* PersistentHistogramAllocator::UseSampleMapRecords(
    480     uint64_t id,
    481     const void* user) {
    482   return sparse_histogram_data_manager_.UseSampleMapRecords(id, user);
    483 }
    484 
    485 void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) {
    486   memory_allocator_->CreateTrackingHistograms(name);
    487 }
    488 
    489 void PersistentHistogramAllocator::UpdateTrackingHistograms() {
    490   memory_allocator_->UpdateTrackingHistograms();
    491 }
    492 
    493 void PersistentHistogramAllocator::ClearLastCreatedReferenceForTesting() {
    494   subtle::NoBarrier_Store(&last_created_, 0);
    495 }
    496 
    497 std::unique_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
    498     PersistentHistogramData* histogram_data_ptr) {
    499   if (!histogram_data_ptr)
    500     return nullptr;
    501 
    502   // Sparse histograms are quite different so handle them as a special case.
    503   if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) {
    504     std::unique_ptr<HistogramBase> histogram =
    505         SparseHistogram::PersistentCreate(this, histogram_data_ptr->name,
    506                                           &histogram_data_ptr->samples_metadata,
    507                                           &histogram_data_ptr->logged_metadata);
    508     DCHECK(histogram);
    509     histogram->SetFlags(histogram_data_ptr->flags);
    510     return histogram;
    511   }
    512 
    513   // Copy the configuration fields from histogram_data_ptr to local storage
    514   // because anything in persistent memory cannot be trusted as it could be
    515   // changed at any moment by a malicious actor that shares access. The local
    516   // values are validated below and then used to create the histogram, knowing
    517   // they haven't changed between validation and use.
    518   int32_t histogram_type = histogram_data_ptr->histogram_type;
    519   int32_t histogram_flags = histogram_data_ptr->flags;
    520   int32_t histogram_minimum = histogram_data_ptr->minimum;
    521   int32_t histogram_maximum = histogram_data_ptr->maximum;
    522   uint32_t histogram_bucket_count = histogram_data_ptr->bucket_count;
    523   uint32_t histogram_ranges_ref = histogram_data_ptr->ranges_ref;
    524   uint32_t histogram_ranges_checksum = histogram_data_ptr->ranges_checksum;
    525 
    526   HistogramBase::Sample* ranges_data =
    527       memory_allocator_->GetAsArray<HistogramBase::Sample>(
    528           histogram_ranges_ref, kTypeIdRangesArray,
    529           PersistentMemoryAllocator::kSizeAny);
    530 
    531   const uint32_t max_buckets =
    532       std::numeric_limits<uint32_t>::max() / sizeof(HistogramBase::Sample);
    533   size_t required_bytes =
    534       (histogram_bucket_count + 1) * sizeof(HistogramBase::Sample);
    535   size_t allocated_bytes =
    536       memory_allocator_->GetAllocSize(histogram_ranges_ref);
    537   if (!ranges_data || histogram_bucket_count < 2 ||
    538       histogram_bucket_count >= max_buckets ||
    539       allocated_bytes < required_bytes) {
    540     return nullptr;
    541   }
    542 
    543   std::unique_ptr<const BucketRanges> created_ranges = CreateRangesFromData(
    544       ranges_data, histogram_ranges_checksum, histogram_bucket_count + 1);
    545   if (!created_ranges)
    546     return nullptr;
    547   const BucketRanges* ranges =
    548       StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
    549           created_ranges.release());
    550 
    551   size_t counts_bytes = CalculateRequiredCountsBytes(histogram_bucket_count);
    552   PersistentMemoryAllocator::Reference counts_ref =
    553       subtle::Acquire_Load(&histogram_data_ptr->counts_ref);
    554   if (counts_bytes == 0 ||
    555       (counts_ref != 0 &&
    556        memory_allocator_->GetAllocSize(counts_ref) < counts_bytes)) {
    557     return nullptr;
    558   }
    559 
    560   // The "counts" data (including both samples and logged samples) is a delayed
    561   // persistent allocation meaning that though its size and storage for a
    562   // reference is defined, no space is reserved until actually needed. When
    563   // it is needed, memory will be allocated from the persistent segment and
    564   // a reference to it stored at the passed address. Other threads can then
    565   // notice the valid reference and access the same data.
    566   DelayedPersistentAllocation counts_data(memory_allocator_.get(),
    567                                           &histogram_data_ptr->counts_ref,
    568                                           kTypeIdCountsArray, counts_bytes, 0);
    569 
    570   // A second delayed allocations is defined using the same reference storage
    571   // location as the first so the allocation of one will automatically be found
    572   // by the other. Within the block, the first half of the space is for "counts"
    573   // and the second half is for "logged counts".
    574   DelayedPersistentAllocation logged_data(
    575       memory_allocator_.get(), &histogram_data_ptr->counts_ref,
    576       kTypeIdCountsArray, counts_bytes, counts_bytes / 2,
    577       /*make_iterable=*/false);
    578 
    579   // Create the right type of histogram.
    580   const char* name = histogram_data_ptr->name;
    581   std::unique_ptr<HistogramBase> histogram;
    582   switch (histogram_type) {
    583     case HISTOGRAM:
    584       histogram = Histogram::PersistentCreate(
    585           name, histogram_minimum, histogram_maximum, ranges, counts_data,
    586           logged_data, &histogram_data_ptr->samples_metadata,
    587           &histogram_data_ptr->logged_metadata);
    588       DCHECK(histogram);
    589       break;
    590     case LINEAR_HISTOGRAM:
    591       histogram = LinearHistogram::PersistentCreate(
    592           name, histogram_minimum, histogram_maximum, ranges, counts_data,
    593           logged_data, &histogram_data_ptr->samples_metadata,
    594           &histogram_data_ptr->logged_metadata);
    595       DCHECK(histogram);
    596       break;
    597     case BOOLEAN_HISTOGRAM:
    598       histogram = BooleanHistogram::PersistentCreate(
    599           name, ranges, counts_data, logged_data,
    600           &histogram_data_ptr->samples_metadata,
    601           &histogram_data_ptr->logged_metadata);
    602       DCHECK(histogram);
    603       break;
    604     case CUSTOM_HISTOGRAM:
    605       histogram = CustomHistogram::PersistentCreate(
    606           name, ranges, counts_data, logged_data,
    607           &histogram_data_ptr->samples_metadata,
    608           &histogram_data_ptr->logged_metadata);
    609       DCHECK(histogram);
    610       break;
    611     default:
    612       return nullptr;
    613   }
    614 
    615   if (histogram) {
    616     DCHECK_EQ(histogram_type, histogram->GetHistogramType());
    617     histogram->SetFlags(histogram_flags);
    618   }
    619 
    620   return histogram;
    621 }
    622 
    623 HistogramBase*
    624 PersistentHistogramAllocator::GetOrCreateStatisticsRecorderHistogram(
    625     const HistogramBase* histogram) {
    626   // This should never be called on the global histogram allocator as objects
    627   // created there are already within the global statistics recorder.
    628   DCHECK_NE(GlobalHistogramAllocator::Get(), this);
    629   DCHECK(histogram);
    630 
    631   HistogramBase* existing =
    632       StatisticsRecorder::FindHistogram(histogram->histogram_name());
    633   if (existing)
    634     return existing;
    635 
    636   // Adding the passed histogram to the SR would cause a problem if the
    637   // allocator that holds it eventually goes away. Instead, create a new
    638   // one from a serialized version. Deserialization calls the appropriate
    639   // FactoryGet() which will create the histogram in the global persistent-
    640   // histogram allocator if such is set.
    641   base::Pickle pickle;
    642   histogram->SerializeInfo(&pickle);
    643   PickleIterator iter(pickle);
    644   existing = DeserializeHistogramInfo(&iter);
    645   if (!existing)
    646     return nullptr;
    647 
    648   // Make sure there is no "serialization" flag set.
    649   DCHECK_EQ(0, existing->flags() & HistogramBase::kIPCSerializationSourceFlag);
    650   // Record the newly created histogram in the SR.
    651   return StatisticsRecorder::RegisterOrDeleteDuplicate(existing);
    652 }
    653 
    654 GlobalHistogramAllocator::~GlobalHistogramAllocator() = default;
    655 
    656 // static
    657 void GlobalHistogramAllocator::CreateWithPersistentMemory(
    658     void* base,
    659     size_t size,
    660     size_t page_size,
    661     uint64_t id,
    662     StringPiece name) {
    663   Set(WrapUnique(
    664       new GlobalHistogramAllocator(std::make_unique<PersistentMemoryAllocator>(
    665           base, size, page_size, id, name, false))));
    666 }
    667 
    668 // static
    669 void GlobalHistogramAllocator::CreateWithLocalMemory(
    670     size_t size,
    671     uint64_t id,
    672     StringPiece name) {
    673   Set(WrapUnique(new GlobalHistogramAllocator(
    674       std::make_unique<LocalPersistentMemoryAllocator>(size, id, name))));
    675 }
    676 
    677 #if !defined(OS_NACL)
    678 // static
    679 bool GlobalHistogramAllocator::CreateWithFile(
    680     const FilePath& file_path,
    681     size_t size,
    682     uint64_t id,
    683     StringPiece name) {
    684   bool exists = PathExists(file_path);
    685   File file(
    686       file_path, File::FLAG_OPEN_ALWAYS | File::FLAG_SHARE_DELETE |
    687                  File::FLAG_READ | File::FLAG_WRITE);
    688 
    689   std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
    690   if (exists) {
    691     size = saturated_cast<size_t>(file.GetLength());
    692     mmfile->Initialize(std::move(file), MemoryMappedFile::READ_WRITE);
    693   } else {
    694     mmfile->Initialize(std::move(file), {0, size},
    695                        MemoryMappedFile::READ_WRITE_EXTEND);
    696   }
    697   if (!mmfile->IsValid() ||
    698       !FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)) {
    699     return false;
    700   }
    701 
    702   Set(WrapUnique(new GlobalHistogramAllocator(
    703       std::make_unique<FilePersistentMemoryAllocator>(std::move(mmfile), size,
    704                                                       id, name, false))));
    705   Get()->SetPersistentLocation(file_path);
    706   return true;
    707 }
    708 
    709 // static
    710 bool GlobalHistogramAllocator::CreateWithActiveFile(const FilePath& base_path,
    711                                                     const FilePath& active_path,
    712                                                     const FilePath& spare_path,
    713                                                     size_t size,
    714                                                     uint64_t id,
    715                                                     StringPiece name) {
    716   // Old "active" becomes "base".
    717   if (!base::ReplaceFile(active_path, base_path, nullptr))
    718     base::DeleteFile(base_path, /*recursive=*/false);
    719   DCHECK(!base::PathExists(active_path));
    720 
    721   // Move any "spare" into "active". Okay to continue if file doesn't exist.
    722   if (!spare_path.empty()) {
    723     base::ReplaceFile(spare_path, active_path, nullptr);
    724     DCHECK(!base::PathExists(spare_path));
    725   }
    726 
    727   return base::GlobalHistogramAllocator::CreateWithFile(active_path, size, id,
    728                                                         name);
    729 }
    730 
    731 // static
    732 bool GlobalHistogramAllocator::CreateWithActiveFileInDir(const FilePath& dir,
    733                                                          size_t size,
    734                                                          uint64_t id,
    735                                                          StringPiece name) {
    736   FilePath base_path, active_path, spare_path;
    737   ConstructFilePaths(dir, name, &base_path, &active_path, &spare_path);
    738   return CreateWithActiveFile(base_path, active_path, spare_path, size, id,
    739                               name);
    740 }
    741 
    742 // static
    743 FilePath GlobalHistogramAllocator::ConstructFilePath(const FilePath& dir,
    744                                                      StringPiece name) {
    745   return dir.AppendASCII(name).AddExtension(
    746       PersistentMemoryAllocator::kFileExtension);
    747 }
    748 
    749 // static
    750 FilePath GlobalHistogramAllocator::ConstructFilePathForUploadDir(
    751     const FilePath& dir,
    752     StringPiece name,
    753     base::Time stamp,
    754     ProcessId pid) {
    755   return ConstructFilePath(
    756       dir,
    757       StringPrintf("%.*s-%lX-%lX", static_cast<int>(name.length()), name.data(),
    758                    static_cast<long>(stamp.ToTimeT()), static_cast<long>(pid)));
    759 }
    760 
    761 // static
    762 bool GlobalHistogramAllocator::ParseFilePath(const FilePath& path,
    763                                              std::string* out_name,
    764                                              Time* out_stamp,
    765                                              ProcessId* out_pid) {
    766   std::string filename = path.BaseName().AsUTF8Unsafe();
    767   std::vector<base::StringPiece> parts = base::SplitStringPiece(
    768       filename, "-.", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
    769   if (parts.size() != 4)
    770     return false;
    771 
    772   if (out_name)
    773     *out_name = parts[0].as_string();
    774 
    775   if (out_stamp) {
    776     int64_t stamp;
    777     if (!HexStringToInt64(parts[1], &stamp))
    778       return false;
    779     *out_stamp = Time::FromTimeT(static_cast<time_t>(stamp));
    780   }
    781 
    782   if (out_pid) {
    783     int64_t pid;
    784     if (!HexStringToInt64(parts[2], &pid))
    785       return false;
    786     *out_pid = static_cast<ProcessId>(pid);
    787   }
    788 
    789   return true;
    790 }
    791 
    792 // static
    793 void GlobalHistogramAllocator::ConstructFilePaths(const FilePath& dir,
    794                                                   StringPiece name,
    795                                                   FilePath* out_base_path,
    796                                                   FilePath* out_active_path,
    797                                                   FilePath* out_spare_path) {
    798   if (out_base_path)
    799     *out_base_path = ConstructFilePath(dir, name);
    800 
    801   if (out_active_path) {
    802     *out_active_path =
    803         ConstructFilePath(dir, name.as_string().append("-active"));
    804   }
    805 
    806   if (out_spare_path) {
    807     *out_spare_path = ConstructFilePath(dir, name.as_string().append("-spare"));
    808   }
    809 }
    810 
    811 // static
    812 void GlobalHistogramAllocator::ConstructFilePathsForUploadDir(
    813     const FilePath& active_dir,
    814     const FilePath& upload_dir,
    815     const std::string& name,
    816     FilePath* out_upload_path,
    817     FilePath* out_active_path,
    818     FilePath* out_spare_path) {
    819   if (out_upload_path) {
    820     *out_upload_path = ConstructFilePathForUploadDir(
    821         upload_dir, name, Time::Now(), GetCurrentProcId());
    822   }
    823 
    824   if (out_active_path) {
    825     *out_active_path =
    826         ConstructFilePath(active_dir, name + std::string("-active"));
    827   }
    828 
    829   if (out_spare_path) {
    830     *out_spare_path =
    831         ConstructFilePath(active_dir, name + std::string("-spare"));
    832   }
    833 }
    834 
    835 // static
    836 bool GlobalHistogramAllocator::CreateSpareFile(const FilePath& spare_path,
    837                                                size_t size) {
    838   FilePath temp_spare_path = spare_path.AddExtension(FILE_PATH_LITERAL(".tmp"));
    839   bool success = true;
    840   {
    841     File spare_file(temp_spare_path, File::FLAG_CREATE_ALWAYS |
    842                                          File::FLAG_READ | File::FLAG_WRITE);
    843     if (!spare_file.IsValid())
    844       return false;
    845 
    846     MemoryMappedFile mmfile;
    847     mmfile.Initialize(std::move(spare_file), {0, size},
    848                       MemoryMappedFile::READ_WRITE_EXTEND);
    849     success = mmfile.IsValid();
    850   }
    851 
    852   if (success)
    853     success = ReplaceFile(temp_spare_path, spare_path, nullptr);
    854 
    855   if (!success)
    856     DeleteFile(temp_spare_path, /*recursive=*/false);
    857 
    858   return success;
    859 }
    860 
    861 // static
    862 bool GlobalHistogramAllocator::CreateSpareFileInDir(const FilePath& dir,
    863                                                     size_t size,
    864                                                     StringPiece name) {
    865   FilePath spare_path;
    866   ConstructFilePaths(dir, name, nullptr, nullptr, &spare_path);
    867   return CreateSpareFile(spare_path, size);
    868 }
    869 #endif  // !defined(OS_NACL)
    870 
    871 // static
    872 void GlobalHistogramAllocator::CreateWithSharedMemoryHandle(
    873     const SharedMemoryHandle& handle,
    874     size_t size) {
    875   std::unique_ptr<SharedMemory> shm(
    876       new SharedMemory(handle, /*readonly=*/false));
    877   if (!shm->Map(size) ||
    878       !SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(*shm)) {
    879     return;
    880   }
    881 
    882   Set(WrapUnique(new GlobalHistogramAllocator(
    883       std::make_unique<SharedPersistentMemoryAllocator>(
    884           std::move(shm), 0, StringPiece(), /*readonly=*/false))));
    885 }
    886 
    887 // static
    888 void GlobalHistogramAllocator::Set(
    889     std::unique_ptr<GlobalHistogramAllocator> allocator) {
    890   // Releasing or changing an allocator is extremely dangerous because it
    891   // likely has histograms stored within it. If the backing memory is also
    892   // also released, future accesses to those histograms will seg-fault.
    893   CHECK(!subtle::NoBarrier_Load(&g_histogram_allocator));
    894   subtle::Release_Store(&g_histogram_allocator,
    895                         reinterpret_cast<uintptr_t>(allocator.release()));
    896   size_t existing = StatisticsRecorder::GetHistogramCount();
    897 
    898   DVLOG_IF(1, existing)
    899       << existing << " histograms were created before persistence was enabled.";
    900 }
    901 
    902 // static
    903 GlobalHistogramAllocator* GlobalHistogramAllocator::Get() {
    904   return reinterpret_cast<GlobalHistogramAllocator*>(
    905       subtle::Acquire_Load(&g_histogram_allocator));
    906 }
    907 
    908 // static
    909 std::unique_ptr<GlobalHistogramAllocator>
    910 GlobalHistogramAllocator::ReleaseForTesting() {
    911   GlobalHistogramAllocator* histogram_allocator = Get();
    912   if (!histogram_allocator)
    913     return nullptr;
    914   PersistentMemoryAllocator* memory_allocator =
    915       histogram_allocator->memory_allocator();
    916 
    917   // Before releasing the memory, it's necessary to have the Statistics-
    918   // Recorder forget about the histograms contained therein; otherwise,
    919   // some operations will try to access them and the released memory.
    920   PersistentMemoryAllocator::Iterator iter(memory_allocator);
    921   const PersistentHistogramData* data;
    922   while ((data = iter.GetNextOfObject<PersistentHistogramData>()) != nullptr) {
    923     StatisticsRecorder::ForgetHistogramForTesting(data->name);
    924   }
    925 
    926   subtle::Release_Store(&g_histogram_allocator, 0);
    927   return WrapUnique(histogram_allocator);
    928 };
    929 
    930 void GlobalHistogramAllocator::SetPersistentLocation(const FilePath& location) {
    931   persistent_location_ = location;
    932 }
    933 
    934 const FilePath& GlobalHistogramAllocator::GetPersistentLocation() const {
    935   return persistent_location_;
    936 }
    937 
    938 bool GlobalHistogramAllocator::WriteToPersistentLocation() {
    939 #if defined(OS_NACL)
    940   // NACL doesn't support file operations, including ImportantFileWriter.
    941   NOTREACHED();
    942   return false;
    943 #else
    944   // Stop if no destination is set.
    945   if (persistent_location_.empty()) {
    946     NOTREACHED() << "Could not write \"" << Name() << "\" persistent histograms"
    947                  << " to file because no location was set.";
    948     return false;
    949   }
    950 
    951   StringPiece contents(static_cast<const char*>(data()), used());
    952   if (!ImportantFileWriter::WriteFileAtomically(persistent_location_,
    953                                                 contents)) {
    954     LOG(ERROR) << "Could not write \"" << Name() << "\" persistent histograms"
    955                << " to file: " << persistent_location_.value();
    956     return false;
    957   }
    958 
    959   return true;
    960 #endif
    961 }
    962 
    963 void GlobalHistogramAllocator::DeletePersistentLocation() {
    964   memory_allocator()->SetMemoryState(PersistentMemoryAllocator::MEMORY_DELETED);
    965 
    966 #if defined(OS_NACL)
    967   NOTREACHED();
    968 #else
    969   if (persistent_location_.empty())
    970     return;
    971 
    972   // Open (with delete) and then immediately close the file by going out of
    973   // scope. This is the only cross-platform safe way to delete a file that may
    974   // be open elsewhere. Open handles will continue to operate normally but
    975   // new opens will not be possible.
    976   File file(persistent_location_,
    977             File::FLAG_OPEN | File::FLAG_READ | File::FLAG_DELETE_ON_CLOSE);
    978 #endif
    979 }
    980 
    981 GlobalHistogramAllocator::GlobalHistogramAllocator(
    982     std::unique_ptr<PersistentMemoryAllocator> memory)
    983     : PersistentHistogramAllocator(std::move(memory)),
    984       import_iterator_(this) {
    985 }
    986 
    987 void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() {
    988   // Skip the import if it's the histogram that was last created. Should a
    989   // race condition cause the "last created" to be overwritten before it
    990   // is recognized here then the histogram will be created and be ignored
    991   // when it is detected as a duplicate by the statistics-recorder. This
    992   // simple check reduces the time of creating persistent histograms by
    993   // about 40%.
    994   Reference record_to_ignore = last_created();
    995 
    996   // There is no lock on this because the iterator is lock-free while still
    997   // guaranteed to only return each entry only once. The StatisticsRecorder
    998   // has its own lock so the Register operation is safe.
    999   while (true) {
   1000     std::unique_ptr<HistogramBase> histogram =
   1001         import_iterator_.GetNextWithIgnore(record_to_ignore);
   1002     if (!histogram)
   1003       break;
   1004     StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release());
   1005   }
   1006 }
   1007 
   1008 }  // namespace base
   1009