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 |