OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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_found_(0), | |
grt (UTC plus 2)
2016/02/04 15:36:42
nit: remove this initializer
bcwhite
2016/02/04 21:51:14
Leftover from a previous design. Odd that it isn'
| |
32 metrics_service_(metrics_service), | |
33 pref_service_(local_state) { | |
34 // Start a background check for pending setup metrics so it can be uploaded | |
grt (UTC plus 2)
2016/02/04 15:36:42
is it appropriate for this to be generalized so th
bcwhite
2016/02/04 21:51:14
I started it as something specific for Setup but t
grt (UTC plus 2)
2016/02/08 18:09:18
In that case, could you update this and other refe
bcwhite
2016/02/09 21:08:45
Done.
| |
35 // during the initial report. | |
36 ScheduleFilesCheck(); | |
37 } | |
38 | |
39 FileMetricsProvider::~FileMetricsProvider() { | |
40 // Destruction of this object can lead to failures because of a task | |
41 // posted on the Worker Pool or because the owned Memory Allocator has | |
grt (UTC plus 2)
2016/02/04 15:36:42
the destruction problems are avoided by following
| |
42 // been passed to the Metrics Service. Both cases can only occur if | |
43 // a Metrics Service has been provided (i.e. not during testing). | |
44 DCHECK(!metrics_service_); | |
45 } | |
46 | |
47 void FileMetricsProvider::RegisterFile(const base::FilePath& path, | |
48 FileType type, | |
49 const std::string& prefs_key) { | |
50 FileInformation* file = new FileInformation(); | |
51 file->path = path; | |
52 file->type = type; | |
53 file->prefs_key = prefs_key; | |
54 | |
55 if (!prefs_key.empty()) { | |
grt (UTC plus 2)
2016/02/04 15:36:43
&& pref_service_
since it could be null as per the
bcwhite
2016/02/04 21:51:14
Done.
| |
56 file->last_seen = base::Time::FromInternalValue( | |
57 pref_service_->GetInt64(metrics::prefs::kSetupMetricsLastSeenPrefix + | |
58 prefs_key)); | |
59 } | |
60 | |
61 base::AutoLock lock(lock_); | |
62 metrics_files_.push_back(scoped_ptr<FileInformation>(file)); | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: scoped_ptr<FileInformation>(file) -> make_sco
bcwhite
2016/02/04 21:51:14
Done.
| |
63 } | |
64 | |
65 // static | |
66 void FileMetricsProvider::RegisterPrefs(PrefRegistrySimple* prefs, | |
67 const std::string& key) { | |
68 prefs->RegisterInt64Pref(metrics::prefs::kSetupMetricsLastSeenPrefix + | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: indentation
bcwhite
2016/02/04 21:51:14
Done.
| |
69 key, 0); | |
70 } | |
71 | |
72 void FileMetricsProvider::OnDidCreateMetricsLog() { | |
73 // Hold off async updates to file lists while processing. | |
74 base::AutoLock lock(lock_); | |
75 | |
76 // Move finished metric files back to list of monitored files. | |
77 FileInformationList::iterator iter; | |
78 for (iter = metrics_found_.begin(); iter != metrics_found_.end();) { | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: define |iter| here with "auto iter = ..."
bcwhite
2016/02/04 21:51:14
Done.
| |
79 auto temp = iter++; | |
80 const FileInformation* file = temp->get(); | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: omit this local var and use temp-> directly b
bcwhite
2016/02/04 21:51:14
I'd rather not. It looks ugly with all the temp->
| |
81 if (!file->allocator && !file->mapped) { | |
82 metrics_files_.push_back(std::move(*temp)); | |
grt (UTC plus 2)
2016/02/04 15:36:43
i believe this line and the next can be replaced w
bcwhite
2016/02/04 21:51:14
Done.
| |
83 metrics_found_.erase(temp); | |
84 } | |
85 } | |
86 | |
87 // Schedule a check to see if there are new metrics to load. If so, they | |
88 // will be reported during the next collection run after this one. The | |
89 // check is run off of the worker-pool so as to not cause delays on the | |
90 // main UI thread (which is currently where metric collection is done). | |
91 ScheduleFilesCheck(); | |
92 } | |
93 | |
94 void FileMetricsProvider::RecordHistogramSnapshots( | |
95 base::HistogramSnapshotManager* hsm) { | |
96 // Hold off async updates to file lists while processing. | |
97 base::AutoLock lock(lock_); | |
98 | |
99 for (auto& file_iter : metrics_found_) { | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: |file_iter| isn't an iterator here, but rathe
bcwhite
2016/02/04 21:51:14
Done.
| |
100 FileInformation* file = file_iter.get(); | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: omit this local var and use the auto'd |file|
bcwhite
2016/02/04 21:51:14
Done.
| |
101 | |
102 if (!file->allocator) { | |
103 DCHECK(file->mapped); | |
104 if (!base::FilePersistentMemoryAllocator::IsFileAcceptable( | |
105 *file->mapped)) { | |
106 // Something is fundamentally wrong with the file. Ignore it. | |
107 LOG(ERROR) << "Metrics file \"" << file->path.AsUTF8Unsafe() | |
grt (UTC plus 2)
2016/02/04 15:36:43
file->path.value() should be fine here
bcwhite
2016/02/04 21:51:14
Done.
| |
108 << "\" is not valid -- ignored."; | |
109 file->mapped.reset(); | |
110 RecordFileAsSeen(file); | |
111 NOTREACHED(); | |
112 continue; | |
113 } | |
114 file->allocator.reset(new base::FilePersistentMemoryAllocator( | |
grt (UTC plus 2)
2016/02/04 15:36:43
change FilePersistentMemoryAllocator so that it ta
bcwhite
2016/02/04 21:51:14
Doing that in a different CL:
https://codereview.c
| |
115 file->mapped.release(), 0, std::string())); | |
116 } | |
117 | |
118 if (file->allocator) { | |
grt (UTC plus 2)
2016/02/04 15:36:43
remove this condition as it will always be true on
bcwhite
2016/02/04 21:51:14
Done.
| |
119 base::PersistentMemoryAllocator::Iterator hist_iter; | |
120 file->allocator->CreateIterator(&hist_iter); | |
121 for (;;) { | |
122 base::HistogramBase* histogram = | |
grt (UTC plus 2)
2016/02/04 15:36:43
use scoped_ptr<base::HistogramBase> rather than a
bcwhite
2016/02/09 21:08:45
Done.
| |
123 base::GetNextPersistentHistogram(file->allocator.get(), &hist_iter); | |
grt (UTC plus 2)
2016/02/04 15:36:43
please update this and the related functions to re
bcwhite
2016/02/09 21:08:45
Okay. It doesn't belong here, though. I'll do it
| |
124 if (!histogram) | |
125 break; | |
126 if (file->type == FILE_HISTOGRAMS_ATOMIC) { | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: omit braces
bcwhite
2016/02/04 21:51:14
Done.
| |
127 hsm->PrepareOnceTakingOwnership(histogram); | |
128 } else { | |
129 hsm->PrepareDeltaTakingOwnership(histogram); | |
130 } | |
131 } | |
132 | |
133 if (file->type == FILE_HISTOGRAMS_ATOMIC) { | |
134 DCHECK(!file->mapped); // Ownership should have moved to allocator. | |
135 file->allocator.reset(); | |
136 RecordFileAsSeen(file); | |
137 } | |
138 } | |
139 } | |
140 } | |
141 | |
142 void FileMetricsProvider::RecordFileAsSeen(FileInformation* file) { | |
143 file->last_seen = base::Time::Now(); | |
144 if (!file->prefs_key.empty()) { | |
grt (UTC plus 2)
2016/02/04 15:36:42
&& pref_service_
bcwhite
2016/02/04 21:51:14
Done.
| |
145 pref_service_->SetInt64(metrics::prefs::kSetupMetricsLastSeenPrefix + | |
146 file->prefs_key, | |
147 file->last_seen.ToInternalValue()); | |
148 } | |
149 } | |
150 | |
151 // static | |
152 void FileMetricsProvider::CheckAndMapNewMetricFiles( | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: often a suffix such as "OnBlockingPool" is ad
bcwhite
2016/02/04 21:51:14
Done.
| |
153 FileMetricsProvider::FileInformationList* files, | |
154 base::Callback<void(FileInformationList*)> callback) { | |
155 for (auto& file : *files) | |
156 CheckAndMapNewMetrics(file.get()); | |
157 callback.Run(files); | |
158 } | |
159 | |
160 // static | |
161 bool FileMetricsProvider::CheckAndMapNewMetrics( | |
162 FileMetricsProvider::FileInformation* file) { | |
163 DCHECK(!file->mapped); | |
164 | |
165 base::File::Info info; | |
166 if (!base::GetFileInfo(file->path, &info) || | |
167 info.is_directory || info.size == 0) { | |
168 return false; | |
169 } | |
170 | |
171 if (file->last_seen >= info.last_modified) | |
172 return false; | |
173 | |
174 // A new file of setup metrics has been found. Map it into memory. | |
175 file->mapped.reset(new base::MemoryMappedFile()); | |
176 file->mapped->Initialize(file->path); | |
grt (UTC plus 2)
2016/02/04 15:36:43
if (file->mapped->Initialize(file->path))
retu
bcwhite
2016/02/04 21:51:14
Done.
| |
177 return true; | |
178 } | |
179 | |
180 void FileMetricsProvider::ScheduleFilesCheck() { | |
181 // Don't do anything if metrics_service is not valid (for testing). | |
182 if (!metrics_service_) | |
183 return; | |
184 | |
185 // TODO(bcwhite): Change this if metric collection moves off UI thread. | |
186 FileInformationList* check_list = new FileInformationList(); | |
187 std::swap(metrics_files_, *check_list); | |
188 bool posted = base::WorkerPool::PostTask( | |
grt (UTC plus 2)
2016/02/04 15:36:42
This should use the BrowserThread BlockingPool rat
| |
189 FROM_HERE, | |
190 base::Bind(&CheckAndMapNewMetricFiles, | |
191 base::Owned(check_list), | |
192 base::Bind(&FileMetricsProvider::RecordFileInformation, | |
193 base::Unretained(this))), | |
grt (UTC plus 2)
2016/02/04 15:36:43
This will lead to a use-after-free if the metrics
| |
194 false); | |
195 DCHECK(posted); | |
grt (UTC plus 2)
2016/02/04 15:36:42
I don't think this is needed. false from PostTask*
| |
196 } | |
197 | |
198 void FileMetricsProvider::RecordFileInformation(FileInformationList* files) { | |
199 // This is a callback and thus possibly not on the same thread as the main | |
200 // metrics collection. | |
201 base::AutoLock lock(lock_); | |
202 | |
203 // Move each processed file to either the "found" list (for processing) or | |
204 // the "files" list (for future checking). | |
205 for (auto& iter : *files) { | |
206 if (iter->mapped) { | |
grt (UTC plus 2)
2016/02/04 15:36:43
nit: omit braces
bcwhite
2016/02/09 21:08:45
Done.
| |
207 metrics_found_.push_back(std::move(iter)); | |
grt (UTC plus 2)
2016/02/04 15:36:43
use splice to move the element. you'll have to cha
bcwhite
2016/02/04 21:51:14
Each move in that case has to delete the value fro
grt (UTC plus 2)
2016/02/08 18:09:18
metrics_files_ and metrics_found_ are both linked
| |
208 } else { | |
209 metrics_files_.push_back(std::move(iter)); | |
grt (UTC plus 2)
2016/02/04 15:36:43
metrics_files_.splice(metrics_files_.end(), *files
bcwhite
2016/02/04 21:51:14
Done.
| |
210 } | |
211 } | |
212 } | |
213 | |
214 } // namespace metrics | |
OLD | NEW |