• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "components/metrics/file_metrics_provider.h"
11 
12 #include <memory>
13 
14 #include "base/files/file_path.h"
15 #include "base/files/file_util.h"
16 #include "base/files/memory_mapped_file.h"
17 #include "base/files/scoped_temp_dir.h"
18 #include "base/functional/bind.h"
19 #include "base/functional/callback.h"
20 #include "base/memory/raw_ptr.h"
21 #include "base/metrics/histogram.h"
22 #include "base/metrics/histogram_base.h"
23 #include "base/metrics/histogram_flattener.h"
24 #include "base/metrics/histogram_snapshot_manager.h"
25 #include "base/metrics/persistent_histogram_allocator.h"
26 #include "base/metrics/persistent_memory_allocator.h"
27 #include "base/metrics/sparse_histogram.h"
28 #include "base/metrics/statistics_recorder.h"
29 #include "base/strings/stringprintf.h"
30 #include "base/synchronization/waitable_event.h"
31 #include "base/test/bind.h"
32 #include "base/test/metrics/histogram_tester.h"
33 #include "base/test/task_environment.h"
34 #include "base/time/time.h"
35 #include "components/metrics/metrics_log.h"
36 #include "components/metrics/metrics_pref_names.h"
37 #include "components/metrics/persistent_system_profile.h"
38 #include "components/prefs/pref_registry_simple.h"
39 #include "components/prefs/testing_pref_service.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
43 #include "third_party/metrics_proto/system_profile.pb.h"
44 
45 namespace {
46 const char kMetricsName[] = "TestMetrics";
47 const char kMergedCountHistogramName[] =
48     "UMA.FileMetricsProvider.TestMetrics.MergedHistogramsCount";
49 const char kMetricsFilename[] = "file.metrics";
50 
WriteSystemProfileToAllocator(base::PersistentHistogramAllocator * allocator)51 void WriteSystemProfileToAllocator(
52     base::PersistentHistogramAllocator* allocator) {
53   metrics::SystemProfileProto profile_proto;
54   // Add a field trial to verify that FileMetricsProvider will produce an
55   // independent log with the written system profile. Similarly for the session
56   // hash.
57   metrics::SystemProfileProto::FieldTrial* trial =
58       profile_proto.add_field_trial();
59   trial->set_name_id(123);
60   trial->set_group_id(456);
61   profile_proto.set_session_hash(789);
62   metrics::PersistentSystemProfile persistent_profile;
63   persistent_profile.RegisterPersistentAllocator(allocator->memory_allocator());
64   persistent_profile.SetSystemProfile(profile_proto, /*complete=*/true);
65 }
66 }  // namespace
67 
68 namespace metrics {
69 
70 class HistogramFlattenerDeltaRecorder : public base::HistogramFlattener {
71  public:
72   HistogramFlattenerDeltaRecorder() = default;
73 
74   HistogramFlattenerDeltaRecorder(const HistogramFlattenerDeltaRecorder&) =
75       delete;
76   HistogramFlattenerDeltaRecorder& operator=(
77       const HistogramFlattenerDeltaRecorder&) = delete;
78 
RecordDelta(const base::HistogramBase & histogram,const base::HistogramSamples & snapshot)79   void RecordDelta(const base::HistogramBase& histogram,
80                    const base::HistogramSamples& snapshot) override {
81     // Only remember locally created histograms; they have exactly 2 chars.
82     if (strlen(histogram.histogram_name()) == 2)
83       recorded_delta_histogram_names_.push_back(histogram.histogram_name());
84   }
85 
GetRecordedDeltaHistogramNames()86   std::vector<std::string> GetRecordedDeltaHistogramNames() {
87     return recorded_delta_histogram_names_;
88   }
89 
90  private:
91   std::vector<std::string> recorded_delta_histogram_names_;
92 };
93 
94 // Exactly the same as FileMetricsProvider, but provides a way to "hook" into
95 // RecordSourcesChecked() and run a callback each time it is called so that it
96 // is easier to individually verify the sources being merged.
97 class TestFileMetricsProvider : public FileMetricsProvider {
98  public:
99   using FileMetricsProvider::FileMetricsProvider;
100 
101   TestFileMetricsProvider(const TestFileMetricsProvider&) = delete;
102   TestFileMetricsProvider& operator=(const TestFileMetricsProvider&) = delete;
103 
104   ~TestFileMetricsProvider() override = default;
105 
106   // Sets the callback to run after RecordSourcesChecked() is called. Used to
107   // individually verify the sources being merged.
SetSourcesCheckedCallback(base::RepeatingClosure callback)108   void SetSourcesCheckedCallback(base::RepeatingClosure callback) {
109     callback_ = std::move(callback);
110   }
111 
112  private:
113   // FileMetricsProvider:
RecordSourcesChecked(SourceInfoList * checked,std::vector<size_t> samples_counts)114   void RecordSourcesChecked(SourceInfoList* checked,
115                             std::vector<size_t> samples_counts) override {
116     if (!callback_.is_null()) {
117       callback_.Run();
118     }
119 
120     FileMetricsProvider::RecordSourcesChecked(checked, samples_counts);
121   }
122 
123   // A callback to run after a call to RecordSourcesChecked().
124   base::RepeatingClosure callback_;
125 };
126 
127 class FileMetricsProviderTest : public testing::TestWithParam<bool> {
128  public:
129   FileMetricsProviderTest(const FileMetricsProviderTest&) = delete;
130   FileMetricsProviderTest& operator=(const FileMetricsProviderTest&) = delete;
131 
132  protected:
133   const size_t kSmallFileSize = 64 << 10;  // 64 KiB
134   const size_t kLargeFileSize =  2 << 20;  //  2 MiB
135 
136   enum : int { kMaxCreateHistograms = 10 };
137 
FileMetricsProviderTest()138   FileMetricsProviderTest()
139       : create_large_files_(GetParam()),
140         statistics_recorder_(
141             base::StatisticsRecorder::CreateTemporaryForTesting()),
142         prefs_(new TestingPrefServiceSimple) {
143     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
144     FileMetricsProvider::RegisterSourcePrefs(prefs_->registry(), kMetricsName);
145   }
146 
~FileMetricsProviderTest()147   ~FileMetricsProviderTest() override {
148     // Clear out any final remaining tasks.
149     task_environment_.RunUntilIdle();
150     DCHECK_EQ(0U, filter_actions_remaining_);
151     // If a global histogram allocator exists at this point then it likely
152     // acquired histograms that will continue to point to the released
153     // memory and potentially cause use-after-free memory corruption.
154     DCHECK(!base::GlobalHistogramAllocator::Get());
155   }
156 
task_environment()157   base::test::TaskEnvironment* task_environment() { return &task_environment_; }
prefs()158   TestingPrefServiceSimple* prefs() { return prefs_.get(); }
temp_dir()159   base::FilePath temp_dir() { return temp_dir_.GetPath(); }
metrics_file()160   base::FilePath metrics_file() {
161     return temp_dir_.GetPath().AppendASCII(kMetricsFilename);
162   }
163 
provider()164   TestFileMetricsProvider* provider() {
165     if (!provider_)
166       provider_ = std::make_unique<TestFileMetricsProvider>(prefs());
167     return provider_.get();
168   }
169 
OnDidCreateMetricsLog()170   void OnDidCreateMetricsLog() {
171     provider()->OnDidCreateMetricsLog();
172   }
173 
HasPreviousSessionData()174   bool HasPreviousSessionData() { return provider()->HasPreviousSessionData(); }
175 
MergeHistogramDeltas()176   void MergeHistogramDeltas() {
177     provider()->MergeHistogramDeltas(/*async=*/false,
178                                      /*done_callback=*/base::DoNothing());
179   }
180 
HasIndependentMetrics()181   bool HasIndependentMetrics() { return provider()->HasIndependentMetrics(); }
182 
ProvideIndependentMetrics(ChromeUserMetricsExtension * uma_proto,base::HistogramSnapshotManager * snapshot_manager)183   bool ProvideIndependentMetrics(
184       ChromeUserMetricsExtension* uma_proto,
185       base::HistogramSnapshotManager* snapshot_manager) {
186     bool success = false;
187     bool success_set = false;
188     provider()->ProvideIndependentMetrics(
189         base::DoNothing(),
190         base::BindOnce(
191             [](bool* success_ptr, bool* set_ptr, bool s) {
192               *success_ptr = s;
193               *set_ptr = true;
194             },
195             &success, &success_set),
196         uma_proto, snapshot_manager);
197 
198     task_environment()->RunUntilIdle();
199     CHECK(success_set);
200     return success;
201   }
202 
RecordInitialHistogramSnapshots(base::HistogramSnapshotManager * snapshot_manager)203   void RecordInitialHistogramSnapshots(
204       base::HistogramSnapshotManager* snapshot_manager) {
205     provider()->RecordInitialHistogramSnapshots(snapshot_manager);
206   }
207 
GetSnapshotHistogramCount()208   size_t GetSnapshotHistogramCount() {
209     // Merge the data from the allocator into the StatisticsRecorder.
210     MergeHistogramDeltas();
211 
212     // Flatten what is known to see what has changed since the last time.
213     HistogramFlattenerDeltaRecorder flattener;
214     base::HistogramSnapshotManager snapshot_manager(&flattener);
215     // "true" to the begin() includes histograms held in persistent storage.
216     base::StatisticsRecorder::PrepareDeltas(true, base::Histogram::kNoFlags,
217                                             base::Histogram::kNoFlags,
218                                             &snapshot_manager);
219     return flattener.GetRecordedDeltaHistogramNames().size();
220   }
221 
GetIndependentHistogramCount()222   size_t GetIndependentHistogramCount() {
223     HistogramFlattenerDeltaRecorder flattener;
224     base::HistogramSnapshotManager snapshot_manager(&flattener);
225     ChromeUserMetricsExtension uma_proto;
226     provider()->ProvideIndependentMetrics(base::DoNothing(),
227                                           base::BindOnce([](bool success) {}),
228                                           &uma_proto, &snapshot_manager);
229 
230     task_environment()->RunUntilIdle();
231     return flattener.GetRecordedDeltaHistogramNames().size();
232   }
233 
CreateGlobalHistograms(int histogram_count)234   void CreateGlobalHistograms(int histogram_count) {
235     DCHECK_GT(kMaxCreateHistograms, histogram_count);
236 
237     // Create both sparse and normal histograms in the allocator. Make them
238     // stability histograms to ensure that the histograms are snapshotted (in
239     // the case of stability logs) or are put into independent logs. Histogram
240     // names must be 2 characters (see HistogramFlattenerDeltaRecorder).
241     created_histograms_[0] = base::SparseHistogram::FactoryGet(
242         "h0", /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
243     created_histograms_[0]->Add(0);
244     for (int i = 1; i < histogram_count; ++i) {
245       created_histograms_[i] = base::Histogram::FactoryGet(
246           base::StringPrintf("h%d", i), 1, 100, 10,
247           /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
248       created_histograms_[i]->Add(i);
249     }
250   }
251 
WriteMetricsFile(const base::FilePath & path,base::PersistentHistogramAllocator * metrics)252   void WriteMetricsFile(const base::FilePath& path,
253                         base::PersistentHistogramAllocator* metrics) {
254     base::File writer(path,
255                       base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
256     // Use DCHECK so the stack-trace will indicate where this was called.
257     DCHECK(writer.IsValid()) << path;
258     size_t file_size = create_large_files_ ? metrics->size() : metrics->used();
259     int written = writer.Write(0, (const char*)metrics->data(), file_size);
260     DCHECK_EQ(static_cast<int>(file_size), written);
261   }
262 
WriteMetricsFileAtTime(const base::FilePath & path,base::PersistentHistogramAllocator * metrics,base::Time write_time)263   void WriteMetricsFileAtTime(const base::FilePath& path,
264                               base::PersistentHistogramAllocator* metrics,
265                               base::Time write_time) {
266     WriteMetricsFile(path, metrics);
267     base::TouchFile(path, write_time, write_time);
268   }
269 
CreateMetricsFileWithHistograms(const base::FilePath & file_path,base::Time write_time,int histogram_count,base::OnceCallback<void (base::PersistentHistogramAllocator *)> callback)270   base::GlobalHistogramAllocator* CreateMetricsFileWithHistograms(
271       const base::FilePath& file_path,
272       base::Time write_time,
273       int histogram_count,
274       base::OnceCallback<void(base::PersistentHistogramAllocator*)> callback) {
275     base::GlobalHistogramAllocator::CreateWithLocalMemory(
276         create_large_files_ ? kLargeFileSize : kSmallFileSize,
277         0, kMetricsName);
278 
279     CreateGlobalHistograms(histogram_count);
280 
281     base::GlobalHistogramAllocator* histogram_allocator =
282         base::GlobalHistogramAllocator::ReleaseForTesting();
283     std::move(callback).Run(histogram_allocator);
284 
285     WriteMetricsFileAtTime(file_path, histogram_allocator, write_time);
286     return histogram_allocator;
287   }
288 
CreateEmptyFile(const base::FilePath & file_path)289   void CreateEmptyFile(const base::FilePath& file_path) {
290     base::File empty(file_path,
291                      base::File::FLAG_CREATE | base::File::FLAG_WRITE);
292   }
293 
CreateMetricsFileWithHistograms(int histogram_count)294   base::GlobalHistogramAllocator* CreateMetricsFileWithHistograms(
295       int histogram_count) {
296     return CreateMetricsFileWithHistograms(
297         metrics_file(), base::Time::Now(), histogram_count,
298         base::BindOnce([](base::PersistentHistogramAllocator* allocator) {}));
299   }
300 
GetCreatedHistogram(int index)301   base::HistogramBase* GetCreatedHistogram(int index) {
302     DCHECK_GT(kMaxCreateHistograms, index);
303     return created_histograms_[index];
304   }
305 
SetFilterActions(FileMetricsProvider::Params * params,const FileMetricsProvider::FilterAction * actions,size_t count)306   void SetFilterActions(FileMetricsProvider::Params* params,
307                         const FileMetricsProvider::FilterAction* actions,
308                         size_t count) {
309     filter_actions_ = actions;
310     filter_actions_remaining_ = count;
311     params->filter = base::BindRepeating(
312         &FileMetricsProviderTest::FilterSourcePath, base::Unretained(this));
313   }
314 
315   const bool create_large_files_;
316 
317  private:
FilterSourcePath(const base::FilePath & path)318   FileMetricsProvider::FilterAction FilterSourcePath(
319       const base::FilePath& path) {
320     DCHECK_LT(0U, filter_actions_remaining_);
321     --filter_actions_remaining_;
322     return *filter_actions_++;
323   }
324 
325   base::test::TaskEnvironment task_environment_;
326   std::unique_ptr<base::StatisticsRecorder> statistics_recorder_;
327   base::ScopedTempDir temp_dir_;
328   std::unique_ptr<TestingPrefServiceSimple> prefs_;
329   std::unique_ptr<TestFileMetricsProvider> provider_;
330   base::HistogramBase* created_histograms_[kMaxCreateHistograms];
331 
332   raw_ptr<const FileMetricsProvider::FilterAction, AllowPtrArithmetic>
333       filter_actions_ = nullptr;
334   size_t filter_actions_remaining_ = 0;
335 };
336 
337 // Run all test cases with both small and large files.
338 INSTANTIATE_TEST_SUITE_P(SmallAndLargeFiles,
339                          FileMetricsProviderTest,
340                          testing::Bool());
341 
TEST_P(FileMetricsProviderTest,AccessMetrics)342 TEST_P(FileMetricsProviderTest, AccessMetrics) {
343   ASSERT_FALSE(PathExists(metrics_file()));
344   base::HistogramTester histogram_tester;
345 
346   base::Time metrics_time = base::Time::Now() - base::Minutes(5);
347   base::GlobalHistogramAllocator* histogram_allocator =
348       CreateMetricsFileWithHistograms(2);
349   ASSERT_TRUE(PathExists(metrics_file()));
350   base::TouchFile(metrics_file(), metrics_time, metrics_time);
351 
352   // Register the file and allow the "checker" task to run.
353   provider()->RegisterSource(
354       FileMetricsProvider::Params(
355           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
356           FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName),
357       /*metrics_reporting_enabled=*/true);
358   histogram_tester.ExpectTotalCount(kMergedCountHistogramName,
359                                     /*expected_count=*/0);
360 
361   // Record embedded snapshots via snapshot-manager.
362   OnDidCreateMetricsLog();
363   task_environment()->RunUntilIdle();
364   EXPECT_EQ(2U, GetSnapshotHistogramCount());
365   histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
366                                       /*expected_bucket_count=*/1);
367   EXPECT_FALSE(base::PathExists(metrics_file()));
368 
369   // Make sure a second call to the snapshot-recorder doesn't break anything.
370   OnDidCreateMetricsLog();
371   task_environment()->RunUntilIdle();
372   EXPECT_EQ(0U, GetSnapshotHistogramCount());
373 
374   // File should have been deleted but recreate it to test behavior should
375   // the file not be deletable by this process.
376   WriteMetricsFileAtTime(metrics_file(), histogram_allocator, metrics_time);
377 
378   // Second full run on the same file should produce nothing.
379   OnDidCreateMetricsLog();
380   task_environment()->RunUntilIdle();
381   EXPECT_EQ(0U, GetSnapshotHistogramCount());
382   histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
383                                       /*expected_bucket_count=*/1);
384   EXPECT_FALSE(base::PathExists(metrics_file()));
385 
386   // Recreate the file to indicate that it is "new" and must be recorded.
387   metrics_time = metrics_time + base::Minutes(1);
388   WriteMetricsFileAtTime(metrics_file(), histogram_allocator, metrics_time);
389 
390   // This run should again have "new" histograms.
391   OnDidCreateMetricsLog();
392   task_environment()->RunUntilIdle();
393   EXPECT_EQ(2U, GetSnapshotHistogramCount());
394   histogram_tester.ExpectUniqueSample(kMergedCountHistogramName, /*sample=*/2,
395                                       /*expected_bucket_count=*/2);
396   EXPECT_FALSE(base::PathExists(metrics_file()));
397 }
398 
TEST_P(FileMetricsProviderTest,AccessTimeLimitedFile)399 TEST_P(FileMetricsProviderTest, AccessTimeLimitedFile) {
400   ASSERT_FALSE(PathExists(metrics_file()));
401 
402   base::Time metrics_time = base::Time::Now() - base::Hours(5);
403   CreateMetricsFileWithHistograms(2);
404   ASSERT_TRUE(PathExists(metrics_file()));
405   base::TouchFile(metrics_file(), metrics_time, metrics_time);
406 
407   // Register the file and allow the "checker" task to run.
408   FileMetricsProvider::Params params(
409       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
410       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
411   params.max_age = base::Hours(1);
412   provider()->RegisterSource(params, /*metrics_reporting_enabled=*/true);
413 
414   // Attempt to access the file should return nothing.
415   OnDidCreateMetricsLog();
416   task_environment()->RunUntilIdle();
417   EXPECT_EQ(0U, GetSnapshotHistogramCount());
418   EXPECT_FALSE(base::PathExists(metrics_file()));
419 }
420 
TEST_P(FileMetricsProviderTest,FilterDelaysFile)421 TEST_P(FileMetricsProviderTest, FilterDelaysFile) {
422   ASSERT_FALSE(PathExists(metrics_file()));
423 
424   base::Time now_time = base::Time::Now();
425   base::Time metrics_time = now_time - base::Minutes(5);
426   CreateMetricsFileWithHistograms(2);
427   ASSERT_TRUE(PathExists(metrics_file()));
428   base::TouchFile(metrics_file(), metrics_time, metrics_time);
429   base::File::Info fileinfo;
430   ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
431   EXPECT_GT(base::Time::Now(), fileinfo.last_modified);
432 
433   // Register the file and allow the "checker" task to run.
434   FileMetricsProvider::Params params(
435       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
436       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
437   const FileMetricsProvider::FilterAction actions[] = {
438       FileMetricsProvider::FILTER_TRY_LATER,
439       FileMetricsProvider::FILTER_PROCESS_FILE};
440   SetFilterActions(&params, actions, std::size(actions));
441   provider()->RegisterSource(params, /*metrics_reporting_enabled=*/true);
442 
443   // Processing the file should touch it but yield no results. File timestamp
444   // accuracy is limited so compare the touched time to a couple seconds past.
445   OnDidCreateMetricsLog();
446   task_environment()->RunUntilIdle();
447   EXPECT_EQ(0U, GetSnapshotHistogramCount());
448   EXPECT_TRUE(base::PathExists(metrics_file()));
449   ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
450   EXPECT_LT(metrics_time, fileinfo.last_modified);
451   EXPECT_LE(now_time - base::Seconds(2), fileinfo.last_modified);
452 
453   // Second full run on the same file should process the file.
454   OnDidCreateMetricsLog();
455   task_environment()->RunUntilIdle();
456   EXPECT_EQ(2U, GetSnapshotHistogramCount());
457   EXPECT_FALSE(base::PathExists(metrics_file()));
458 }
459 
TEST_P(FileMetricsProviderTest,FilterSkipsFile)460 TEST_P(FileMetricsProviderTest, FilterSkipsFile) {
461   ASSERT_FALSE(PathExists(metrics_file()));
462 
463   base::Time now_time = base::Time::Now();
464   base::Time metrics_time = now_time - base::Minutes(5);
465   CreateMetricsFileWithHistograms(2);
466   ASSERT_TRUE(PathExists(metrics_file()));
467   base::TouchFile(metrics_file(), metrics_time, metrics_time);
468   base::File::Info fileinfo;
469   ASSERT_TRUE(base::GetFileInfo(metrics_file(), &fileinfo));
470   EXPECT_GT(base::Time::Now(), fileinfo.last_modified);
471 
472   // Register the file and allow the "checker" task to run.
473   FileMetricsProvider::Params params(
474       metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
475       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
476   const FileMetricsProvider::FilterAction actions[] = {
477       FileMetricsProvider::FILTER_SKIP_FILE};
478   SetFilterActions(&params, actions, std::size(actions));
479   provider()->RegisterSource(params, /*metrics_reporting_enabled=*/true);
480 
481   // Processing the file should delete it.
482   OnDidCreateMetricsLog();
483   task_environment()->RunUntilIdle();
484   EXPECT_EQ(0U, GetSnapshotHistogramCount());
485   EXPECT_FALSE(base::PathExists(metrics_file()));
486 }
487 
TEST_P(FileMetricsProviderTest,AccessDirectory)488 TEST_P(FileMetricsProviderTest, AccessDirectory) {
489   ASSERT_FALSE(PathExists(metrics_file()));
490 
491   base::GlobalHistogramAllocator::CreateWithLocalMemory(
492       64 << 10, 0, kMetricsName);
493   base::GlobalHistogramAllocator* allocator =
494       base::GlobalHistogramAllocator::Get();
495   base::HistogramBase* histogram;
496 
497   // Create files starting with a timestamp a few minutes back.
498   base::Time base_time = base::Time::Now() - base::Minutes(10);
499 
500   // Create some files in an odd order. The files are "touched" back in time to
501   // ensure that each file has a later timestamp on disk than the previous one.
502   base::ScopedTempDir metrics_files;
503   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
504   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII(".foo.pma"),
505                          allocator, base_time);
506   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("_bar.pma"),
507                          allocator, base_time);
508   // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
509   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
510   histogram->Add(1);
511   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
512                          allocator, base_time + base::Minutes(1));
513 
514   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
515   histogram->Add(2);
516   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
517                          allocator, base_time + base::Minutes(2));
518 
519   histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
520   histogram->Add(3);
521   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
522                          allocator, base_time + base::Minutes(3));
523 
524   histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
525   histogram->Add(3);
526   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
527                          allocator, base_time + base::Minutes(4));
528 
529   base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
530                   base_time + base::Minutes(5), base_time + base::Minutes(5));
531 
532   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("baz"), allocator,
533                          base_time + base::Minutes(6));
534 
535   // The global allocator has to be detached here so that no metrics created
536   // by code called below get stored in it as that would make for potential
537   // use-after-free operations if that code is called again.
538   base::GlobalHistogramAllocator::ReleaseForTesting();
539 
540   // Register the file and allow the "checker" task to run.
541   provider()->RegisterSource(
542       FileMetricsProvider::Params(
543           metrics_files.GetPath(),
544           FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
545           FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName),
546       /*metrics_reporting_enabled=*/true);
547 
548   // Record embedded snapshots via snapshot-manager.
549   std::vector<uint32_t> actual_order;
550   provider()->SetSourcesCheckedCallback(base::BindLambdaForTesting(
551       [&] { actual_order.push_back(GetSnapshotHistogramCount()); }));
552   OnDidCreateMetricsLog();
553   task_environment()->RunUntilIdle();
554 
555   // Files could come out in the order: a1, c2, d4, b3. They are recognizable by
556   // the number of histograms contained within each. The "0" is the last merge
557   // done, which detects that there are no more files to merge.
558   EXPECT_THAT(actual_order, testing::ElementsAre(1, 2, 4, 3, 0));
559 
560   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
561   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
562   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
563   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
564   EXPECT_TRUE(
565       base::PathExists(metrics_files.GetPath().AppendASCII(".foo.pma")));
566   EXPECT_TRUE(
567       base::PathExists(metrics_files.GetPath().AppendASCII("_bar.pma")));
568   EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("baz")));
569 }
570 
TEST_P(FileMetricsProviderTest,AccessDirectoryWithInvalidFiles)571 TEST_P(FileMetricsProviderTest, AccessDirectoryWithInvalidFiles) {
572   ASSERT_FALSE(PathExists(metrics_file()));
573 
574   // Create files starting with a timestamp a few minutes back.
575   base::Time base_time = base::Time::Now() - base::Minutes(10);
576 
577   base::ScopedTempDir metrics_files;
578   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
579   base::FilePath dir = metrics_files.GetPath();
580 
581   CreateMetricsFileWithHistograms(
582       dir.AppendASCII("h1.pma"),
583       base_time + base::Minutes(1), 1,
584       base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
585         allocator->memory_allocator()->SetMemoryState(
586             base::PersistentMemoryAllocator::MEMORY_DELETED);
587       }));
588 
589   CreateMetricsFileWithHistograms(
590       dir.AppendASCII("h2.pma"),
591       base_time + base::Minutes(2), 2,
592       base::BindOnce(&WriteSystemProfileToAllocator));
593 
594   CreateMetricsFileWithHistograms(
595       dir.AppendASCII("h3.pma"),
596       base_time + base::Minutes(3), 3,
597       base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
598         allocator->memory_allocator()->SetMemoryState(
599             base::PersistentMemoryAllocator::MEMORY_DELETED);
600       }));
601 
602   CreateEmptyFile(dir.AppendASCII("h4.pma"));
603   base::TouchFile(dir.AppendASCII("h4.pma"),
604                   base_time + base::Minutes(4), base_time + base::Minutes(4));
605 
606   // Register the file and allow the "checker" task to run.
607   provider()->RegisterSource(
608       FileMetricsProvider::Params(
609           dir,
610           FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
611           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName),
612       /*metrics_reporting_enabled=*/true);
613 
614   // No files yet.
615   EXPECT_EQ(0U, GetIndependentHistogramCount());
616   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h1.pma")));
617   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h2.pma")));
618   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h3.pma")));
619   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h4.pma")));
620 
621   // H1 should be skipped and H2 available.
622   OnDidCreateMetricsLog();
623   task_environment()->RunUntilIdle();
624   EXPECT_FALSE(base::PathExists(dir.AppendASCII("h1.pma")));
625   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h2.pma")));
626   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h3.pma")));
627   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h4.pma")));
628 
629   // H2 should be read and the file deleted.
630   EXPECT_EQ(2U, GetIndependentHistogramCount());
631   task_environment()->RunUntilIdle();
632   EXPECT_FALSE(base::PathExists(dir.AppendASCII("h2.pma")));
633 
634   // Nothing else should be found but the last (valid but empty) file will
635   // stick around to be processed later (should it get expanded).
636   EXPECT_EQ(0U, GetIndependentHistogramCount());
637   task_environment()->RunUntilIdle();
638   EXPECT_FALSE(base::PathExists(dir.AppendASCII("h3.pma")));
639   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h4.pma")));
640 }
641 
TEST_P(FileMetricsProviderTest,AccessTimeLimitedDirectory)642 TEST_P(FileMetricsProviderTest, AccessTimeLimitedDirectory) {
643   ASSERT_FALSE(PathExists(metrics_file()));
644 
645   base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
646                                                         kMetricsName);
647   base::GlobalHistogramAllocator* allocator =
648       base::GlobalHistogramAllocator::Get();
649   base::HistogramBase* histogram;
650 
651   // Create one old file and one new file. Histogram names must be 2 characters
652   // (see HistogramFlattenerDeltaRecorder).
653   base::ScopedTempDir metrics_files;
654   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
655   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
656   histogram->Add(1);
657   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
658                          allocator, base::Time::Now() - base::Hours(1));
659 
660   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
661   histogram->Add(2);
662   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
663                          allocator, base::Time::Now());
664 
665   // The global allocator has to be detached here so that no metrics created
666   // by code called below get stored in it as that would make for potential
667   // use-after-free operations if that code is called again.
668   base::GlobalHistogramAllocator::ReleaseForTesting();
669 
670   // Register the file and allow the "checker" task to run.
671   FileMetricsProvider::Params params(
672       metrics_files.GetPath(),
673       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
674       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
675   params.max_age = base::Minutes(30);
676   provider()->RegisterSource(params, /*metrics_reporting_enabled=*/true);
677 
678   // Only b2, with 2 histograms, should be read.
679   OnDidCreateMetricsLog();
680   task_environment()->RunUntilIdle();
681   EXPECT_EQ(2U, GetSnapshotHistogramCount());
682   OnDidCreateMetricsLog();
683   task_environment()->RunUntilIdle();
684   EXPECT_EQ(0U, GetSnapshotHistogramCount());
685 
686   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
687   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
688 }
689 
TEST_P(FileMetricsProviderTest,AccessCountLimitedDirectory)690 TEST_P(FileMetricsProviderTest, AccessCountLimitedDirectory) {
691   ASSERT_FALSE(PathExists(metrics_file()));
692 
693   base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
694                                                         kMetricsName);
695   base::GlobalHistogramAllocator* allocator =
696       base::GlobalHistogramAllocator::Get();
697   base::HistogramBase* histogram;
698 
699   // Create one old file and one new file. Histogram names must be 2 characters
700   // (see HistogramFlattenerDeltaRecorder).
701   base::ScopedTempDir metrics_files;
702   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
703   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
704   histogram->Add(1);
705   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
706                          allocator, base::Time::Now() - base::Hours(1));
707 
708   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
709   histogram->Add(2);
710   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
711                          allocator, base::Time::Now());
712 
713   // The global allocator has to be detached here so that no metrics created
714   // by code called below get stored in it as that would make for potential
715   // use-after-free operations if that code is called again.
716   base::GlobalHistogramAllocator::ReleaseForTesting();
717 
718   // Register the file and allow the "checker" task to run.
719   FileMetricsProvider::Params params(
720       metrics_files.GetPath(),
721       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
722       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
723   params.max_dir_files = 1;
724   provider()->RegisterSource(params, /*metrics_reporting_enabled=*/true);
725 
726   // Only b2, with 2 histograms, should be read.
727   OnDidCreateMetricsLog();
728   task_environment()->RunUntilIdle();
729   EXPECT_EQ(2U, GetSnapshotHistogramCount());
730   OnDidCreateMetricsLog();
731   task_environment()->RunUntilIdle();
732   EXPECT_EQ(0U, GetSnapshotHistogramCount());
733 
734   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
735   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
736 }
737 
TEST_P(FileMetricsProviderTest,AccessSizeLimitedDirectory)738 TEST_P(FileMetricsProviderTest, AccessSizeLimitedDirectory) {
739   // This only works with large files that are big enough to count.
740   if (!create_large_files_)
741     return;
742 
743   ASSERT_FALSE(PathExists(metrics_file()));
744 
745   size_t file_size_kib = 64;
746   base::GlobalHistogramAllocator::CreateWithLocalMemory(file_size_kib << 10, 0,
747                                                         kMetricsName);
748   base::GlobalHistogramAllocator* allocator =
749       base::GlobalHistogramAllocator::Get();
750   base::HistogramBase* histogram;
751 
752   // Create one old file and one new file. Histogram names must be 2 characters
753   // (see HistogramFlattenerDeltaRecorder).
754   base::ScopedTempDir metrics_files;
755   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
756   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
757   histogram->Add(1);
758   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
759                          allocator, base::Time::Now() - base::Hours(1));
760 
761   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
762   histogram->Add(2);
763   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b2.pma"),
764                          allocator, base::Time::Now());
765 
766   // The global allocator has to be detached here so that no metrics created
767   // by code called below get stored in it as that would make for potential
768   // use-after-free operations if that code is called again.
769   base::GlobalHistogramAllocator::ReleaseForTesting();
770 
771   // Register the file and allow the "checker" task to run.
772   FileMetricsProvider::Params params(
773       metrics_files.GetPath(),
774       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
775       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
776   params.max_dir_kib = file_size_kib + 1;
777   provider()->RegisterSource(params, /*metrics_reporting_enabled=*/true);
778 
779   // Only b2, with 2 histograms, should be read.
780   OnDidCreateMetricsLog();
781   task_environment()->RunUntilIdle();
782   EXPECT_EQ(2U, GetSnapshotHistogramCount());
783   OnDidCreateMetricsLog();
784   task_environment()->RunUntilIdle();
785   EXPECT_EQ(0U, GetSnapshotHistogramCount());
786 
787   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
788   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b2.pma")));
789 }
790 
TEST_P(FileMetricsProviderTest,AccessFilteredDirectory)791 TEST_P(FileMetricsProviderTest, AccessFilteredDirectory) {
792   ASSERT_FALSE(PathExists(metrics_file()));
793 
794   base::GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10, 0,
795                                                         kMetricsName);
796   base::GlobalHistogramAllocator* allocator =
797       base::GlobalHistogramAllocator::Get();
798   base::HistogramBase* histogram;
799 
800   // Create files starting with a timestamp a few minutes back.
801   base::Time base_time = base::Time::Now() - base::Minutes(10);
802 
803   // Create some files in an odd order. The files are "touched" back in time to
804   // ensure that each file has a later timestamp on disk than the previous one.
805   base::ScopedTempDir metrics_files;
806   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
807   // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
808   histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
809   histogram->Add(1);
810   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
811                          allocator, base_time + base::Minutes(1));
812 
813   histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
814   histogram->Add(2);
815   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
816                          allocator, base_time + base::Minutes(2));
817 
818   histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
819   histogram->Add(3);
820   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
821                          allocator, base_time + base::Minutes(3));
822 
823   histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
824   histogram->Add(3);
825   WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
826                          allocator, base_time + base::Minutes(4));
827 
828   base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
829                   base_time + base::Minutes(5), base_time + base::Minutes(5));
830 
831   // The global allocator has to be detached here so that no metrics created
832   // by code called below get stored in it as that would make for potential
833   // use-after-free operations if that code is called again.
834   base::GlobalHistogramAllocator::ReleaseForTesting();
835 
836   // Register the file and allow the "checker" task to run.
837   FileMetricsProvider::Params params(
838       metrics_files.GetPath(),
839       FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
840       FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName);
841   const FileMetricsProvider::FilterAction actions[] = {
842       FileMetricsProvider::FILTER_PROCESS_FILE,   // a1
843       FileMetricsProvider::FILTER_TRY_LATER,      // c2
844       FileMetricsProvider::FILTER_SKIP_FILE,      // d4
845       FileMetricsProvider::FILTER_PROCESS_FILE,   // b3
846       FileMetricsProvider::FILTER_PROCESS_FILE};  // c2 (again)
847   SetFilterActions(&params, actions, std::size(actions));
848   provider()->RegisterSource(params, /*metrics_reporting_enabled=*/true);
849 
850   // Record embedded snapshots via snapshot-manager.
851   std::vector<uint32_t> actual_order;
852   provider()->SetSourcesCheckedCallback(base::BindLambdaForTesting(
853       [&] { actual_order.push_back(GetSnapshotHistogramCount()); }));
854   OnDidCreateMetricsLog();
855   task_environment()->RunUntilIdle();
856 
857   // Files could come out in the order: a1, b3, c2. They are recognizable by the
858   // number of histograms contained within each. The "0" is the last merge done,
859   // which detects that there are no more files to merge.
860   EXPECT_THAT(actual_order, testing::ElementsAre(1, 3, 2, 0));
861 
862   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
863   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
864   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
865   EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
866 }
867 
TEST_P(FileMetricsProviderTest,AccessReadWriteMetrics)868 TEST_P(FileMetricsProviderTest, AccessReadWriteMetrics) {
869   // Create a global histogram allocator that maps to a file.
870   ASSERT_FALSE(PathExists(metrics_file()));
871   base::GlobalHistogramAllocator::CreateWithFile(
872       metrics_file(),
873       create_large_files_ ? kLargeFileSize : kSmallFileSize,
874       0, kMetricsName);
875   CreateGlobalHistograms(2);
876   ASSERT_TRUE(PathExists(metrics_file()));
877   base::HistogramBase* h0 = GetCreatedHistogram(0);
878   base::HistogramBase* h1 = GetCreatedHistogram(1);
879   DCHECK(h0);
880   DCHECK(h1);
881   base::GlobalHistogramAllocator::ReleaseForTesting();
882 
883   // Register the file and allow the "checker" task to run.
884   provider()->RegisterSource(
885       FileMetricsProvider::Params(
886           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
887           FileMetricsProvider::ASSOCIATE_CURRENT_RUN),
888       /*metrics_reporting_enabled=*/true);
889 
890   // Record embedded snapshots via snapshot-manager.
891   OnDidCreateMetricsLog();
892   task_environment()->RunUntilIdle();
893   EXPECT_EQ(2U, GetSnapshotHistogramCount());
894   EXPECT_TRUE(base::PathExists(metrics_file()));
895 
896   // Make sure a second call to the snapshot-recorder doesn't break anything.
897   OnDidCreateMetricsLog();
898   task_environment()->RunUntilIdle();
899   EXPECT_EQ(0U, GetSnapshotHistogramCount());
900   EXPECT_TRUE(base::PathExists(metrics_file()));
901 
902   // Change a histogram and ensure that it's counted.
903   h0->Add(0);
904   EXPECT_EQ(1U, GetSnapshotHistogramCount());
905   EXPECT_TRUE(base::PathExists(metrics_file()));
906 
907   // Change the other histogram and verify.
908   h1->Add(11);
909   EXPECT_EQ(1U, GetSnapshotHistogramCount());
910   EXPECT_TRUE(base::PathExists(metrics_file()));
911 }
912 
TEST_P(FileMetricsProviderTest,AccessInitialMetrics)913 TEST_P(FileMetricsProviderTest, AccessInitialMetrics) {
914   ASSERT_FALSE(PathExists(metrics_file()));
915   CreateMetricsFileWithHistograms(2);
916 
917   // Register the file and allow the "checker" task to run.
918   ASSERT_TRUE(PathExists(metrics_file()));
919   provider()->RegisterSource(
920       FileMetricsProvider::Params(
921           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
922           FileMetricsProvider::ASSOCIATE_PREVIOUS_RUN, kMetricsName),
923       /*metrics_reporting_enabled=*/true);
924 
925   // Record embedded snapshots via snapshot-manager.
926   ASSERT_TRUE(HasPreviousSessionData());
927   task_environment()->RunUntilIdle();
928   {
929     HistogramFlattenerDeltaRecorder flattener;
930     base::HistogramSnapshotManager snapshot_manager(&flattener);
931     RecordInitialHistogramSnapshots(&snapshot_manager);
932     EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
933   }
934   EXPECT_TRUE(base::PathExists(metrics_file()));
935   OnDidCreateMetricsLog();
936   task_environment()->RunUntilIdle();
937   EXPECT_FALSE(base::PathExists(metrics_file()));
938 
939   // A run for normal histograms should produce nothing.
940   CreateMetricsFileWithHistograms(2);
941   OnDidCreateMetricsLog();
942   task_environment()->RunUntilIdle();
943   EXPECT_EQ(0U, GetSnapshotHistogramCount());
944   EXPECT_TRUE(base::PathExists(metrics_file()));
945   OnDidCreateMetricsLog();
946   task_environment()->RunUntilIdle();
947   EXPECT_TRUE(base::PathExists(metrics_file()));
948 }
949 
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsWithoutProfile)950 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsWithoutProfile) {
951   ASSERT_FALSE(PathExists(metrics_file()));
952   CreateMetricsFileWithHistograms(2);
953 
954   // Register the file and allow the "checker" task to run.
955   ASSERT_TRUE(PathExists(metrics_file()));
956   provider()->RegisterSource(
957       FileMetricsProvider::Params(
958           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
959           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName),
960       /*metrics_reporting_enabled=*/true);
961 
962   // Record embedded snapshots via snapshot-manager.
963   OnDidCreateMetricsLog();
964   task_environment()->RunUntilIdle();
965   {
966     HistogramFlattenerDeltaRecorder flattener;
967     base::HistogramSnapshotManager snapshot_manager(&flattener);
968     ChromeUserMetricsExtension uma_proto;
969 
970     // A read of metrics with internal profiles should return nothing.
971     EXPECT_FALSE(HasIndependentMetrics());
972     EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
973   }
974   EXPECT_TRUE(base::PathExists(metrics_file()));
975   OnDidCreateMetricsLog();
976   task_environment()->RunUntilIdle();
977   EXPECT_FALSE(base::PathExists(metrics_file()));
978 }
979 
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsWithProfile)980 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsWithProfile) {
981   ASSERT_FALSE(PathExists(metrics_file()));
982   CreateMetricsFileWithHistograms(
983       metrics_file(), base::Time::Now(), 2,
984       base::BindOnce(&WriteSystemProfileToAllocator));
985 
986   // Register the file and allow the "checker" task to run.
987   ASSERT_TRUE(PathExists(metrics_file()));
988   provider()->RegisterSource(
989       FileMetricsProvider::Params(
990           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
991           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName),
992       /*metrics_reporting_enabled=*/true);
993 
994   // Record embedded snapshots via snapshot-manager.
995   OnDidCreateMetricsLog();
996   task_environment()->RunUntilIdle();
997   {
998     HistogramFlattenerDeltaRecorder flattener;
999     base::HistogramSnapshotManager snapshot_manager(&flattener);
1000     RecordInitialHistogramSnapshots(&snapshot_manager);
1001     EXPECT_EQ(0U, flattener.GetRecordedDeltaHistogramNames().size());
1002 
1003     // A read of metrics with internal profiles should return one result, and
1004     // the independent log generated should have the embedded system profile.
1005     ChromeUserMetricsExtension uma_proto;
1006     EXPECT_TRUE(HasIndependentMetrics());
1007     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1008     ASSERT_TRUE(uma_proto.has_system_profile());
1009     ASSERT_EQ(1, uma_proto.system_profile().field_trial_size());
1010     EXPECT_EQ(123U, uma_proto.system_profile().field_trial(0).name_id());
1011     EXPECT_EQ(456U, uma_proto.system_profile().field_trial(0).group_id());
1012     EXPECT_EQ(789U, uma_proto.system_profile().session_hash());
1013     EXPECT_FALSE(HasIndependentMetrics());
1014     EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1015   }
1016   task_environment()->RunUntilIdle();
1017   EXPECT_FALSE(base::PathExists(metrics_file()));
1018 }
1019 
TEST_P(FileMetricsProviderTest,AccessEmbeddedFallbackMetricsWithoutProfile)1020 TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithoutProfile) {
1021   ASSERT_FALSE(PathExists(metrics_file()));
1022   CreateMetricsFileWithHistograms(2);
1023 
1024   // Register the file and allow the "checker" task to run.
1025   ASSERT_TRUE(PathExists(metrics_file()));
1026   provider()->RegisterSource(
1027       FileMetricsProvider::Params(
1028           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1029           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
1030           kMetricsName),
1031       /*metrics_reporting_enabled=*/true);
1032 
1033   // Record embedded snapshots via snapshot-manager.
1034   ASSERT_TRUE(HasPreviousSessionData());
1035   task_environment()->RunUntilIdle();
1036   {
1037     HistogramFlattenerDeltaRecorder flattener;
1038     base::HistogramSnapshotManager snapshot_manager(&flattener);
1039     RecordInitialHistogramSnapshots(&snapshot_manager);
1040     EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
1041 
1042     // A read of metrics with internal profiles should return nothing.
1043     ChromeUserMetricsExtension uma_proto;
1044     EXPECT_FALSE(HasIndependentMetrics());
1045     EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1046   }
1047   EXPECT_TRUE(base::PathExists(metrics_file()));
1048   OnDidCreateMetricsLog();
1049   task_environment()->RunUntilIdle();
1050   EXPECT_FALSE(base::PathExists(metrics_file()));
1051 }
1052 
TEST_P(FileMetricsProviderTest,AccessEmbeddedFallbackMetricsWithProfile)1053 TEST_P(FileMetricsProviderTest, AccessEmbeddedFallbackMetricsWithProfile) {
1054   ASSERT_FALSE(PathExists(metrics_file()));
1055   CreateMetricsFileWithHistograms(
1056       metrics_file(), base::Time::Now(), 2,
1057       base::BindOnce(&WriteSystemProfileToAllocator));
1058 
1059   // Register the file and allow the "checker" task to run.
1060   ASSERT_TRUE(PathExists(metrics_file()));
1061   provider()->RegisterSource(
1062       FileMetricsProvider::Params(
1063           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1064           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN,
1065           kMetricsName),
1066       /*metrics_reporting_enabled=*/true);
1067 
1068   // Record embedded snapshots via snapshot-manager.
1069   EXPECT_FALSE(HasPreviousSessionData());
1070   task_environment()->RunUntilIdle();
1071   {
1072     HistogramFlattenerDeltaRecorder flattener;
1073     base::HistogramSnapshotManager snapshot_manager(&flattener);
1074     RecordInitialHistogramSnapshots(&snapshot_manager);
1075     EXPECT_EQ(0U, flattener.GetRecordedDeltaHistogramNames().size());
1076 
1077     // A read of metrics with internal profiles should return one result.
1078     ChromeUserMetricsExtension uma_proto;
1079     EXPECT_TRUE(HasIndependentMetrics());
1080     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1081     EXPECT_FALSE(HasIndependentMetrics());
1082     EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1083   }
1084   task_environment()->RunUntilIdle();
1085   EXPECT_FALSE(base::PathExists(metrics_file()));
1086 }
1087 
TEST_P(FileMetricsProviderTest,AccessEmbeddedProfileMetricsFromDir)1088 TEST_P(FileMetricsProviderTest, AccessEmbeddedProfileMetricsFromDir) {
1089   const int file_count = 3;
1090   base::Time file_base_time = base::Time::Now();
1091   std::vector<base::FilePath> file_names;
1092   for (int i = 0; i < file_count; ++i) {
1093     CreateMetricsFileWithHistograms(
1094         metrics_file(), base::Time::Now(), 2,
1095         base::BindOnce(&WriteSystemProfileToAllocator));
1096     ASSERT_TRUE(PathExists(metrics_file()));
1097     char new_name[] = "hX";
1098     new_name[1] = '1' + i;
1099     base::FilePath file_name = temp_dir().AppendASCII(new_name).AddExtension(
1100         base::PersistentMemoryAllocator::kFileExtension);
1101     base::Time file_time = file_base_time - base::Minutes(file_count - i);
1102     base::TouchFile(metrics_file(), file_time, file_time);
1103     base::Move(metrics_file(), file_name);
1104     file_names.push_back(std::move(file_name));
1105   }
1106 
1107   // Register the file and allow the "checker" task to run.
1108   provider()->RegisterSource(
1109       FileMetricsProvider::Params(
1110           temp_dir(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
1111           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE),
1112       /*metrics_reporting_enabled=*/true);
1113 
1114   OnDidCreateMetricsLog();
1115   task_environment()->RunUntilIdle();
1116 
1117   // A read of metrics with internal profiles should return one result.
1118   HistogramFlattenerDeltaRecorder flattener;
1119   base::HistogramSnapshotManager snapshot_manager(&flattener);
1120   ChromeUserMetricsExtension uma_proto;
1121   for (int i = 0; i < file_count; ++i) {
1122     EXPECT_TRUE(HasIndependentMetrics()) << i;
1123     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager)) << i;
1124     task_environment()->RunUntilIdle();
1125   }
1126   EXPECT_FALSE(HasIndependentMetrics());
1127   EXPECT_FALSE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1128 
1129   OnDidCreateMetricsLog();
1130   task_environment()->RunUntilIdle();
1131   for (const auto& file_name : file_names)
1132     EXPECT_FALSE(base::PathExists(file_name));
1133 }
1134 
TEST_P(FileMetricsProviderTest,RecordInitialHistogramSnapshotsStabilityHistograms)1135 TEST_P(FileMetricsProviderTest,
1136        RecordInitialHistogramSnapshotsStabilityHistograms) {
1137   // Create a metrics file with 2 non-stability histograms and 2 stability
1138   // histograms. Histogram names must be 2 characters (see
1139   // HistogramFlattenerDeltaRecorder).
1140   ASSERT_FALSE(PathExists(metrics_file()));
1141   base::GlobalHistogramAllocator::CreateWithLocalMemory(
1142       create_large_files_ ? kLargeFileSize : kSmallFileSize, 0, kMetricsName);
1143   base::HistogramBase* h0 = base::SparseHistogram::FactoryGet(
1144       "h0", /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1145   h0->Add(0);
1146   base::HistogramBase* h1 = base::SparseHistogram::FactoryGet(
1147       "h1", /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1148   h1->Add(0);
1149   base::HistogramBase* h2 = base::Histogram::FactoryGet(
1150       "h2", 1, 100, 10,
1151       /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1152   h2->Add(0);
1153   base::HistogramBase* h3 = base::Histogram::FactoryGet(
1154       "h3", 1, 100, 10,
1155       /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1156   h3->Add(0);
1157   base::GlobalHistogramAllocator* histogram_allocator =
1158       base::GlobalHistogramAllocator::ReleaseForTesting();
1159   WriteMetricsFileAtTime(metrics_file(), histogram_allocator,
1160                          base::Time::Now());
1161   ASSERT_TRUE(PathExists(metrics_file()));
1162 
1163   // Register the file and allow the "checker" task to run.
1164   provider()->RegisterSource(
1165       FileMetricsProvider::Params(
1166           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1167           FileMetricsProvider::ASSOCIATE_PREVIOUS_RUN, kMetricsName),
1168       /*metrics_reporting_enabled=*/true);
1169   ASSERT_TRUE(HasPreviousSessionData());
1170   task_environment()->RunUntilIdle();
1171 
1172   // Record embedded snapshots via snapshot-manager.
1173   HistogramFlattenerDeltaRecorder flattener;
1174   base::HistogramSnapshotManager snapshot_manager(&flattener);
1175   RecordInitialHistogramSnapshots(&snapshot_manager);
1176 
1177   // Verify that only the stability histograms were snapshotted.
1178   EXPECT_THAT(flattener.GetRecordedDeltaHistogramNames(),
1179               testing::ElementsAre("h0", "h2"));
1180 
1181   // The metrics file should eventually be deleted.
1182   EXPECT_TRUE(base::PathExists(metrics_file()));
1183   OnDidCreateMetricsLog();
1184   task_environment()->RunUntilIdle();
1185   EXPECT_FALSE(base::PathExists(metrics_file()));
1186 }
1187 
TEST_P(FileMetricsProviderTest,IndependentLogContainsUmaHistograms)1188 TEST_P(FileMetricsProviderTest, IndependentLogContainsUmaHistograms) {
1189   ASSERT_FALSE(PathExists(metrics_file()));
1190   // Create a metrics file with 2 UMA histograms and 2 non-UMA histograms.
1191   // Histogram names must be 2 characters (see HistogramFlattenerDeltaRecorder).
1192   base::GlobalHistogramAllocator::CreateWithLocalMemory(
1193       create_large_files_ ? kLargeFileSize : kSmallFileSize, 0, kMetricsName);
1194   base::HistogramBase* h0 = base::SparseHistogram::FactoryGet(
1195       "h0", /*flags=*/base::HistogramBase::Flags::kUmaTargetedHistogramFlag);
1196   h0->Add(0);
1197   base::HistogramBase* h1 = base::SparseHistogram::FactoryGet(
1198       "h1", /*flags=*/base::HistogramBase::Flags::kNoFlags);
1199   h1->Add(0);
1200   base::HistogramBase* h2 = base::Histogram::FactoryGet(
1201       "h2", 1, 100, 10,
1202       /*flags=*/base::HistogramBase::Flags::kUmaStabilityHistogramFlag);
1203   h2->Add(0);
1204   base::HistogramBase* h3 = base::Histogram::FactoryGet(
1205       "h3", 1, 100, 10,
1206       /*flags=*/base::HistogramBase::Flags::kNoFlags);
1207   h3->Add(0);
1208   base::GlobalHistogramAllocator* histogram_allocator =
1209       base::GlobalHistogramAllocator::ReleaseForTesting();
1210   // Write a system profile so that an independent log can successfully be
1211   // created from the metrics file.
1212   WriteSystemProfileToAllocator(histogram_allocator);
1213   WriteMetricsFileAtTime(metrics_file(), histogram_allocator,
1214                          base::Time::Now());
1215   ASSERT_TRUE(PathExists(metrics_file()));
1216 
1217   // Register the file and allow the "checker" task to run.
1218   provider()->RegisterSource(
1219       FileMetricsProvider::Params(
1220           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1221           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName),
1222       /*metrics_reporting_enabled=*/true);
1223   OnDidCreateMetricsLog();
1224   task_environment()->RunUntilIdle();
1225 
1226   // Verify that the independent log provided only contains UMA histograms (both
1227   // stability and non-stability).
1228   ChromeUserMetricsExtension uma_proto;
1229   HistogramFlattenerDeltaRecorder flattener;
1230   base::HistogramSnapshotManager snapshot_manager(&flattener);
1231   EXPECT_TRUE(HasIndependentMetrics());
1232   EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1233   EXPECT_THAT(flattener.GetRecordedDeltaHistogramNames(),
1234               testing::ElementsAre("h0", "h2"));
1235 
1236   // The metrics file should eventually be deleted.
1237   task_environment()->RunUntilIdle();
1238   EXPECT_FALSE(base::PathExists(metrics_file()));
1239 }
1240 
1241 // Verifies that if the embedded system profile in the file does not contain
1242 // a client UUID, the generated independent log's client ID is not overwritten.
TEST_P(FileMetricsProviderTest,EmbeddedProfileWithoutClientUuid)1243 TEST_P(FileMetricsProviderTest, EmbeddedProfileWithoutClientUuid) {
1244   ASSERT_FALSE(PathExists(metrics_file()));
1245   CreateMetricsFileWithHistograms(
1246       metrics_file(), base::Time::Now(), 2,
1247       base::BindOnce(&WriteSystemProfileToAllocator));
1248 
1249   // Register the file and allow the "checker" task to run.
1250   ASSERT_TRUE(PathExists(metrics_file()));
1251   provider()->RegisterSource(
1252       FileMetricsProvider::Params(
1253           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1254           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName),
1255       /*metrics_reporting_enabled=*/true);
1256 
1257   // Record embedded snapshots via snapshot-manager.
1258   OnDidCreateMetricsLog();
1259   task_environment()->RunUntilIdle();
1260   {
1261     HistogramFlattenerDeltaRecorder flattener;
1262     base::HistogramSnapshotManager snapshot_manager(&flattener);
1263 
1264     // Since the embedded system profile has no client_uuid set (see
1265     // WriteSystemProfileToAllocator()), the client ID written in |uma_proto|
1266     // should be kept.
1267     ChromeUserMetricsExtension uma_proto;
1268     uma_proto.set_client_id(1);
1269     EXPECT_TRUE(HasIndependentMetrics());
1270     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1271     EXPECT_EQ(uma_proto.client_id(), 1U);
1272   }
1273   task_environment()->RunUntilIdle();
1274   EXPECT_FALSE(base::PathExists(metrics_file()));
1275 }
1276 
1277 // Verifies that if the embedded system profile in the file contains a client
1278 // UUID, it is used as the generated independent log's client ID.
TEST_P(FileMetricsProviderTest,EmbeddedProfileWithClientUuid)1279 TEST_P(FileMetricsProviderTest, EmbeddedProfileWithClientUuid) {
1280   ASSERT_FALSE(PathExists(metrics_file()));
1281   static constexpr char kProfileClientUuid[] = "abc";
1282   CreateMetricsFileWithHistograms(
1283       metrics_file(), base::Time::Now(), 2,
1284       base::BindOnce([](base::PersistentHistogramAllocator* allocator) {
1285         metrics::SystemProfileProto profile_proto;
1286         profile_proto.set_client_uuid(kProfileClientUuid);
1287 
1288         metrics::PersistentSystemProfile persistent_profile;
1289         persistent_profile.RegisterPersistentAllocator(
1290             allocator->memory_allocator());
1291         persistent_profile.SetSystemProfile(profile_proto, /*complete=*/true);
1292       }));
1293 
1294   // Register the file and allow the "checker" task to run.
1295   ASSERT_TRUE(PathExists(metrics_file()));
1296   provider()->RegisterSource(
1297       FileMetricsProvider::Params(
1298           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1299           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName),
1300       /*metrics_reporting_enabled=*/true);
1301 
1302   // Record embedded snapshots via snapshot-manager.
1303   OnDidCreateMetricsLog();
1304   task_environment()->RunUntilIdle();
1305   {
1306     HistogramFlattenerDeltaRecorder flattener;
1307     base::HistogramSnapshotManager snapshot_manager(&flattener);
1308 
1309     // Since the embedded system profile contains a client_uuid, the client ID
1310     // in |uma_proto| should be overwritten.
1311     ChromeUserMetricsExtension uma_proto;
1312     uma_proto.set_client_id(1);
1313     EXPECT_TRUE(HasIndependentMetrics());
1314     EXPECT_TRUE(ProvideIndependentMetrics(&uma_proto, &snapshot_manager));
1315     EXPECT_NE(uma_proto.client_id(), 1U);
1316     EXPECT_EQ(uma_proto.client_id(), MetricsLog::Hash(kProfileClientUuid));
1317   }
1318   task_environment()->RunUntilIdle();
1319   EXPECT_FALSE(base::PathExists(metrics_file()));
1320 }
1321 
TEST_P(FileMetricsProviderTest,MetricsDisabledRegisterAtomicFile)1322 TEST_P(FileMetricsProviderTest, MetricsDisabledRegisterAtomicFile) {
1323   ASSERT_FALSE(PathExists(metrics_file()));
1324   CreateMetricsFileWithHistograms(
1325       metrics_file(), base::Time::Now() - base::Minutes(10), 1,
1326       base::BindOnce(&WriteSystemProfileToAllocator));
1327   EXPECT_TRUE(base::PathExists(metrics_file()));
1328 
1329   EXPECT_TRUE(base::PathExists(metrics_file()));
1330   provider()->RegisterSource(
1331       FileMetricsProvider::Params(
1332           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE,
1333           FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName),
1334       /*metrics_reporting_enabled=*/false);
1335 
1336   task_environment()->RunUntilIdle();
1337   EXPECT_FALSE(base::PathExists(metrics_file()));
1338 }
1339 
TEST_P(FileMetricsProviderTest,MetricsDisabledRegisterAtomicDir)1340 TEST_P(FileMetricsProviderTest, MetricsDisabledRegisterAtomicDir) {
1341   base::ScopedTempDir metrics_files;
1342   EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
1343   base::FilePath dir = metrics_files.GetPath();
1344 
1345   CreateMetricsFileWithHistograms(
1346       dir.AppendASCII("h1.pma"), base::Time::Now() - base::Minutes(10), 1,
1347       base::BindOnce(&WriteSystemProfileToAllocator));
1348   // Also create an empty file there to test the multiple-files in dir case.
1349   CreateEmptyFile(dir.AppendASCII("h2.pma"));
1350 
1351   EXPECT_TRUE(base::PathExists(dir));
1352   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h1.pma")));
1353   EXPECT_TRUE(base::PathExists(dir.AppendASCII("h2.pma")));
1354   provider()->RegisterSource(
1355       FileMetricsProvider::Params(
1356           metrics_files.GetPath(),
1357           FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
1358           FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, kMetricsName),
1359       /*metrics_reporting_enabled=*/false);
1360 
1361   task_environment()->RunUntilIdle();
1362   EXPECT_FALSE(base::PathExists(dir));
1363 }
1364 
TEST_P(FileMetricsProviderTest,MetricsDisabledRegisterActiveFile)1365 TEST_P(FileMetricsProviderTest, MetricsDisabledRegisterActiveFile) {
1366   ASSERT_FALSE(PathExists(metrics_file()));
1367   CreateMetricsFileWithHistograms(
1368       metrics_file(), base::Time::Now() - base::Minutes(10), 1,
1369       base::BindOnce(&WriteSystemProfileToAllocator));
1370   EXPECT_TRUE(base::PathExists(metrics_file()));
1371 
1372   provider()->RegisterSource(
1373       FileMetricsProvider::Params(
1374           metrics_file(), FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE,
1375           FileMetricsProvider::ASSOCIATE_CURRENT_RUN, kMetricsName),
1376       /*metrics_reporting_enabled=*/false);
1377 
1378   task_environment()->RunUntilIdle();
1379   // Active file should not be deleted.
1380   EXPECT_TRUE(base::PathExists(metrics_file()));
1381 }
1382 
1383 }  // namespace metrics
1384