Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 "components/metrics/file_metrics_provider.h" | |
| 6 | |
| 7 #include "base/command_line.h" | |
| 8 #include "base/files/file.h" | |
| 9 #include "base/files/file_util.h" | |
| 10 #include "base/files/memory_mapped_file.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/metrics/histogram_base.h" | |
| 13 #include "base/metrics/histogram_persistence.h" | |
| 14 #include "base/metrics/persistent_memory_allocator.h" | |
| 15 #include "base/prefs/pref_registry_simple.h" | |
| 16 #include "base/prefs/pref_service.h" | |
| 17 #include "base/threading/worker_pool.h" | |
| 18 #include "base/time/time.h" | |
| 19 #include "components/metrics/metrics_pref_names.h" | |
| 20 #include "components/metrics/metrics_service.h" | |
| 21 | |
| 22 namespace metrics { | |
| 23 | |
| 24 // Out-of-line constructor and destructor needed for code efficiency. | |
| 25 FileMetricsProvider::FileInformation::FileInformation() {} | |
| 26 FileMetricsProvider::FileInformation::~FileInformation() {} | |
| 27 | |
| 28 FileMetricsProvider::FileMetricsProvider( | |
| 29 metrics::MetricsService* metrics_service, | |
| 30 PrefService* local_state) | |
| 31 : metrics_service_(metrics_service), | |
| 32 pref_service_(local_state) { | |
| 33 // Start a background check for pending setup metrics so it can be uploaded | |
| 34 // during the initial report. | |
| 35 ScheduleFilesCheck(); | |
| 36 } | |
| 37 | |
| 38 FileMetricsProvider::~FileMetricsProvider() { | |
| 39 // Destruction of this object can lead to failures because of a task | |
| 40 // posted on the Worker Pool or because the owned Memory Allocator has | |
| 41 // been passed to the Metrics Service. Both cases can only occur if | |
| 42 // a Metrics Service has been provided (i.e. not during testing). | |
| 43 DCHECK(!metrics_service_); | |
| 44 } | |
| 45 | |
| 46 void FileMetricsProvider::RegisterFile(const base::FilePath& path, | |
| 47 FileType type, | |
| 48 const base::StringPiece& prefs_key) { | |
| 49 FileInformation* file = new FileInformation(); | |
| 50 file->path = path; | |
| 51 file->type = type; | |
| 52 file->prefs_key = prefs_key.as_string(); | |
| 53 | |
| 54 if (pref_service_ && !prefs_key.empty()) { | |
| 55 file->last_seen = base::Time::FromInternalValue( | |
| 56 pref_service_->GetInt64(metrics::prefs::kSetupMetricsLastSeenPrefix + | |
| 57 prefs_key.as_string())); | |
| 58 } | |
| 59 | |
| 60 base::AutoLock lock(lock_); | |
| 61 metrics_files_.push_back(make_scoped_ptr(file)); | |
| 62 } | |
| 63 | |
| 64 // static | |
| 65 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs, | |
| 66 const base::StringPiece& key) { | |
| 67 prefs->RegisterInt64Pref(metrics::prefs::kSetupMetricsLastSeenPrefix + | |
| 68 key.as_string(), 0); | |
| 69 } | |
| 70 | |
| 71 void FileMetricsProvider::OnDidCreateMetricsLog() { | |
|
grt (UTC plus 2)
2016/02/08 18:09:19
nit: move these two functions down below RecordFil
bcwhite
2016/02/09 21:08:46
Done.
| |
| 72 // Hold off async updates to file lists while processing. | |
| 73 base::AutoLock lock(lock_); | |
| 74 | |
| 75 // Move finished metric files back to list of monitored files. | |
| 76 for (auto iter = metrics_found_.begin(); iter != metrics_found_.end();) { | |
| 77 auto temp = iter++; | |
| 78 const FileInformation* file = temp->get(); | |
| 79 if (!file->allocator && !file->mapped) | |
| 80 metrics_files_.splice(metrics_files_.end(), metrics_found_, temp); | |
| 81 } | |
| 82 | |
| 83 // Schedule a check to see if there are new metrics to load. If so, they | |
| 84 // will be reported during the next collection run after this one. The | |
| 85 // check is run off of the worker-pool so as to not cause delays on the | |
| 86 // main UI thread (which is currently where metric collection is done). | |
| 87 ScheduleFilesCheck(); | |
| 88 } | |
| 89 | |
| 90 void FileMetricsProvider::RecordHistogramSnapshots( | |
| 91 base::HistogramSnapshotManager* hsm) { | |
| 92 // Hold off async updates to file lists while processing. | |
| 93 base::AutoLock lock(lock_); | |
| 94 | |
| 95 for (auto& file : metrics_found_) { | |
| 96 if (!file->allocator) { | |
| 97 DCHECK(file->mapped); | |
| 98 if (!base::FilePersistentMemoryAllocator::IsFileAcceptable( | |
| 99 *file->mapped)) { | |
| 100 // Something is fundamentally wrong with the file. Ignore it. | |
| 101 LOG(ERROR) << "Metrics file \"" << file->path.value() | |
| 102 << "\" is not valid -- ignored."; | |
| 103 file->mapped.reset(); | |
| 104 RecordFileAsSeen(file.get()); | |
| 105 NOTREACHED(); | |
| 106 continue; | |
| 107 } | |
| 108 file->allocator.reset(new base::FilePersistentMemoryAllocator( | |
| 109 file->mapped.release(), 0, std::string())); | |
| 110 } | |
| 111 | |
| 112 base::PersistentMemoryAllocator::Iterator hist_iter; | |
| 113 file->allocator->CreateIterator(&hist_iter); | |
| 114 for (;;) { | |
| 115 base::HistogramBase* histogram = | |
| 116 base::GetNextPersistentHistogram(file->allocator.get(), &hist_iter); | |
| 117 if (!histogram) | |
| 118 break; | |
| 119 if (file->type == FILE_HISTOGRAMS_ATOMIC) | |
| 120 hsm->PrepareOnceTakingOwnership(histogram); | |
| 121 else | |
| 122 hsm->PrepareDeltaTakingOwnership(histogram); | |
| 123 } | |
| 124 | |
| 125 if (file->type == FILE_HISTOGRAMS_ATOMIC) { | |
| 126 DCHECK(!file->mapped); // Ownership should have moved to allocator. | |
| 127 file->allocator.reset(); | |
| 128 RecordFileAsSeen(file.get()); | |
| 129 } | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 void FileMetricsProvider::RecordFileAsSeen(FileInformation* file) { | |
| 134 file->last_seen = base::Time::Now(); | |
| 135 if (pref_service_ && !file->prefs_key.empty()) { | |
| 136 pref_service_->SetInt64(metrics::prefs::kSetupMetricsLastSeenPrefix + | |
| 137 file->prefs_key, | |
| 138 file->last_seen.ToInternalValue()); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 // static | |
| 143 void FileMetricsProvider::CheckAndMapNewMetricFilesOnBlockingPool( | |
| 144 FileMetricsProvider::FileInformationList* files, | |
| 145 base::Callback<void(FileInformationList*)> callback) { | |
| 146 for (auto& file : *files) | |
| 147 CheckAndMapNewMetrics(file.get()); | |
| 148 callback.Run(files); | |
| 149 } | |
| 150 | |
| 151 // static | |
| 152 bool FileMetricsProvider::CheckAndMapNewMetrics( | |
| 153 FileMetricsProvider::FileInformation* file) { | |
| 154 DCHECK(!file->mapped); | |
| 155 | |
| 156 base::File::Info info; | |
| 157 if (!base::GetFileInfo(file->path, &info) || | |
| 158 info.is_directory || info.size == 0) { | |
| 159 return false; | |
| 160 } | |
| 161 | |
| 162 if (file->last_seen >= info.last_modified) | |
| 163 return false; | |
| 164 | |
| 165 // A new file of setup metrics has been found. Map it into memory. | |
| 166 file->mapped.reset(new base::MemoryMappedFile()); | |
| 167 if (!file->mapped->Initialize(file->path)) { | |
| 168 NOTREACHED(); | |
| 169 return false; | |
|
grt (UTC plus 2)
2016/02/08 18:09:19
the |mapped| scoped_ptr must also be reset since i
bcwhite
2016/02/09 21:08:46
Done.
| |
| 170 } | |
| 171 return true; | |
| 172 } | |
| 173 | |
| 174 void FileMetricsProvider::ScheduleFilesCheck() { | |
| 175 // Don't do anything if metrics_service is not valid (for testing). | |
| 176 if (!metrics_service_) | |
| 177 return; | |
| 178 | |
| 179 // TODO(bcwhite): Change this if metric collection moves off UI thread. | |
| 180 FileInformationList* check_list = new FileInformationList(); | |
| 181 std::swap(metrics_files_, *check_list); | |
| 182 bool posted = base::WorkerPool::PostTask( | |
| 183 FROM_HERE, | |
| 184 base::Bind(&CheckAndMapNewMetricFilesOnBlockingPool, | |
| 185 base::Owned(check_list), | |
| 186 base::Bind(&FileMetricsProvider::RecordFileInformation, | |
| 187 base::Unretained(this))), | |
| 188 false); | |
| 189 DCHECK(posted); | |
| 190 } | |
| 191 | |
| 192 void FileMetricsProvider::RecordFileInformation(FileInformationList* files) { | |
| 193 // This is a callback and thus possibly not on the same thread as the main | |
| 194 // metrics collection. | |
| 195 base::AutoLock lock(lock_); | |
| 196 | |
| 197 // Move each processed file to either the "found" list (for processing) or | |
| 198 // the "files" list (for future checking). | |
| 199 for (auto& iter : *files) { | |
| 200 if (iter->mapped) | |
| 201 metrics_found_.push_back(std::move(iter)); | |
| 202 else | |
| 203 metrics_files_.push_back(std::move(iter)); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 } // namespace metrics | |
| OLD | NEW |