Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: chrome/browser/chromeos/system/statistics_provider.cc

Issue 10078017: Added asynchronous notification of readiness to the StatisticsProvider, and (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Don't use base::Unretained. Rebased. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/system/statistics_provider.h" 5 #include "chrome/browser/chromeos/system/statistics_provider.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
8 #include "base/chromeos/chromeos_version.h" 9 #include "base/chromeos/chromeos_version.h"
9 #include "base/file_path.h" 10 #include "base/file_path.h"
10 #include "base/file_util.h" 11 #include "base/file_util.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/memory/singleton.h" 13 #include "base/memory/singleton.h"
14 #include "base/message_loop.h"
13 #include "base/synchronization/waitable_event.h" 15 #include "base/synchronization/waitable_event.h"
14 #include "base/time.h" 16 #include "base/time.h"
15 #include "base/chromeos/chromeos_version.h" 17 #include "base/chromeos/chromeos_version.h"
16 #include "chrome/browser/chromeos/system/name_value_pairs_parser.h" 18 #include "chrome/browser/chromeos/system/name_value_pairs_parser.h"
17 #include "chrome/common/child_process_logging.h" 19 #include "chrome/common/child_process_logging.h"
18 #include "chrome/common/chrome_version_info.h" 20 #include "chrome/common/chrome_version_info.h"
19 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
20 22
21 using content::BrowserThread; 23 using content::BrowserThread;
22 24
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
55 const char kMachineOSInfoDelim[] = "\n"; 57 const char kMachineOSInfoDelim[] = "\n";
56 58
57 // File to get VPD info from, and key/value delimiters of the file. 59 // File to get VPD info from, and key/value delimiters of the file.
58 const char kVpdFile[] = "/var/log/vpd_2.0.txt"; 60 const char kVpdFile[] = "/var/log/vpd_2.0.txt";
59 const char kVpdEq[] = "="; 61 const char kVpdEq[] = "=";
60 const char kVpdDelim[] = "\n"; 62 const char kVpdDelim[] = "\n";
61 63
62 // Timeout that we should wait for statistics to get loaded 64 // Timeout that we should wait for statistics to get loaded
63 const int kTimeoutSecs = 3; 65 const int kTimeoutSecs = 3;
64 66
67 // Helper to invoke |callbacks| on the UI thread.
68 void NotifyOnUI(std::vector<base::Closure>* callbacks) {
69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
70 for (std::vector<base::Closure>::iterator it = callbacks->begin();
71 it != callbacks->end(); ++it) {
72 it->Run();
73 }
74 }
75
65 } // namespace 76 } // namespace
66 77
67 // The StatisticsProvider implementation used in production. 78 // The StatisticsProvider implementation used in production.
68 class StatisticsProviderImpl : public StatisticsProvider { 79 class StatisticsProviderImpl : public StatisticsProvider {
69 public: 80 public:
70 // StatisticsProvider implementation: 81 // StatisticsProvider implementation:
71 virtual bool GetMachineStatistic(const std::string& name, 82 virtual bool GetMachineStatistic(const std::string& name,
72 std::string* result) OVERRIDE; 83 std::string* result) OVERRIDE;
73 84
85 virtual void WhenReady(const base::Closure& callback) OVERRIDE;
86
74 static StatisticsProviderImpl* GetInstance(); 87 static StatisticsProviderImpl* GetInstance();
75 88
76 private: 89 private:
77 friend struct DefaultSingletonTraits<StatisticsProviderImpl>; 90 friend struct DefaultSingletonTraits<StatisticsProviderImpl>;
78 91
79 StatisticsProviderImpl(); 92 StatisticsProviderImpl();
80 93
81 // Starts loading the machine statistcs. 94 // Starts loading the machine statistcs.
82 void StartLoadingMachineStatistics(); 95 void StartLoadingMachineStatistics();
83 96
84 // Loads the machine statistcs by examining the system. 97 // Loads the machine statistcs by examining the system.
85 void LoadMachineStatistics(); 98 void LoadMachineStatistics();
86 99
87 NameValuePairsParser::NameValueMap machine_info_; 100 NameValuePairsParser::NameValueMap machine_info_;
88 base::WaitableEvent on_statistics_loaded_; 101 base::WaitableEvent on_statistics_loaded_;
102 std::vector<base::Closure> callbacks_;
89 103
90 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderImpl); 104 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderImpl);
91 }; 105 };
92 106
93 bool StatisticsProviderImpl::GetMachineStatistic( 107 bool StatisticsProviderImpl::GetMachineStatistic(
94 const std::string& name, std::string* result) { 108 const std::string& name, std::string* result) {
jar (doing other things) 2012/04/24 18:37:40 nit: arguments should be aligned, one per line.
Joao da Silva 2012/04/27 09:47:48 Done.
95 VLOG(1) << "Statistic is requested for " << name; 109 VLOG(1) << "Statistic is requested for " << name;
96 // Block if the statistics are not loaded yet. Per LOG(WARNING) below, 110 // Block if the statistics are not loaded yet. Per LOG(WARNING) below,
97 // the statistics are loaded before requested as of now. For regular 111 // the statistics are loaded before requested as of now. For regular
98 // sessions (i.e. not OOBE), statistics are first requested when the 112 // sessions (i.e. not OOBE), statistics are first requested when the
99 // user is logging in so we have plenty of time to load the data 113 // user is logging in so we have plenty of time to load the data
100 // beforehand. 114 // beforehand.
101 // 115 //
102 // If you see the warning appeared for regular sessions, it probably 116 // If you see the warning appeared for regular sessions, it probably
103 // means that there is new client code that uses the statistics in the 117 // means that there is new client code that uses the statistics in the
104 // very early stage of the browser startup. The statistic name should be 118 // very early stage of the browser startup. The statistic name should be
105 // helpful to identify the caller. 119 // helpful to identify the caller.
106 if (!on_statistics_loaded_.IsSignaled()) { 120 if (!on_statistics_loaded_.IsSignaled()) {
107 LOG(WARNING) << "Waiting to load statistics. Requested statistic: " 121 LOG(WARNING) << "Waiting to load statistics. Requested statistic: "
jar (doing other things) 2012/04/24 18:37:40 To reduce the size of the binary, brett made a big
Joao da Silva 2012/04/27 09:47:48 Agree, done.
108 << name; 122 << name;
109 on_statistics_loaded_.TimedWait(base::TimeDelta::FromSeconds(kTimeoutSecs)); 123 on_statistics_loaded_.TimedWait(base::TimeDelta::FromSeconds(kTimeoutSecs));
jar (doing other things) 2012/04/24 18:37:40 IMO, the timeout should definitely be part of the
Joao da Silva 2012/04/27 09:47:48 This is definitely questionable and can surprise c
110 124
111 if (!on_statistics_loaded_.IsSignaled()) { 125 if (!on_statistics_loaded_.IsSignaled()) {
112 LOG(ERROR) << "Statistics weren't loaded after waiting! " 126 LOG(ERROR) << "Statistics weren't loaded after waiting! "
113 << "Requested statistic: " << name; 127 << "Requested statistic: " << name;
114 return false; 128 return false;
115 } 129 }
116 } 130 }
117 131
118 NameValuePairsParser::NameValueMap::iterator iter = machine_info_.find(name); 132 NameValuePairsParser::NameValueMap::iterator iter = machine_info_.find(name);
119 if (iter != machine_info_.end()) { 133 if (iter != machine_info_.end()) {
120 *result = iter->second; 134 *result = iter->second;
121 return true; 135 return true;
122 } 136 }
123 return false; 137 return false;
jar (doing other things) 2012/04/24 18:37:40 This API makes it impossible to tell whether there
Joao da Silva 2012/04/27 09:47:48 This problem doesn't exist with the async notifica
jar (doing other things) 2012/04/27 18:00:38 I think what you're saying is that you plan to rem
Joao da Silva 2012/05/15 13:52:47 This API is used in a couple of places that aren't
124 } 138 }
125 139
140 void StatisticsProviderImpl::WhenReady(const base::Closure& callback) {
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
142 if (on_statistics_loaded_.IsSignaled()) {
143 // Don't assume the caller is re-entrant.
144 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
145 } else {
146 callbacks_.push_back(callback);
147 }
148 }
149
126 // manual_reset needs to be true, as we want to keep the signaled state. 150 // manual_reset needs to be true, as we want to keep the signaled state.
127 StatisticsProviderImpl::StatisticsProviderImpl() 151 StatisticsProviderImpl::StatisticsProviderImpl()
128 : on_statistics_loaded_(true /* manual_reset */, 152 : on_statistics_loaded_(true /* manual_reset */,
129 false /* initially_signaled */) { 153 false /* initially_signaled */) {
130 StartLoadingMachineStatistics(); 154 StartLoadingMachineStatistics();
131 } 155 }
132 156
133 void StatisticsProviderImpl::StartLoadingMachineStatistics() { 157 void StatisticsProviderImpl::StartLoadingMachineStatistics() {
134 VLOG(1) << "Started loading statistics"; 158 VLOG(1) << "Started loading statistics";
135 BrowserThread::PostBlockingPoolTask( 159 BrowserThread::PostBlockingPoolTask(
136 FROM_HERE, 160 FROM_HERE,
137 base::Bind(&StatisticsProviderImpl::LoadMachineStatistics, 161 base::Bind(&StatisticsProviderImpl::LoadMachineStatistics,
138 base::Unretained(this))); 162 base::Unretained(this)));
139 } 163 }
140 164
141 void StatisticsProviderImpl::LoadMachineStatistics() { 165 void StatisticsProviderImpl::LoadMachineStatistics() {
142 NameValuePairsParser parser(&machine_info_); 166 NameValuePairsParser parser(&machine_info_);
143 167
144 // Parse all of the key/value pairs from the crossystem tool. 168 // Parse all of the key/value pairs from the crossystem tool.
145 if (!parser.ParseNameValuePairsFromTool( 169 if (!parser.ParseNameValuePairsFromTool(
146 arraysize(kCrosSystemTool), kCrosSystemTool, kCrosSystemEq, 170 arraysize(kCrosSystemTool), kCrosSystemTool, kCrosSystemEq,
147 kCrosSystemDelim, kCrosSystemCommentDelim)) { 171 kCrosSystemDelim, kCrosSystemCommentDelim)) {
148 LOG(WARNING) << "There were errors parsing the output of " 172 LOG(WARNING) << "There were errors parsing the output of "
jar (doing other things) 2012/04/24 18:37:40 Shouldn't there be action taken to rectify this si
Joao da Silva 2012/04/27 09:47:48 Yes indeed! Added a UMA_HISTOGRAM_BOOLEAN to sampl
149 << kCrosSystemTool << "."; 173 << kCrosSystemTool << ".";
150 } 174 }
151 175
152 // Ensure that the hardware class key is present with the expected 176 // Ensure that the hardware class key is present with the expected
153 // key name, and if it couldn't be retrieved, that the value is "unknown". 177 // key name, and if it couldn't be retrieved, that the value is "unknown".
154 std::string hardware_class = machine_info_[kHardwareClassCrosSystemKey]; 178 std::string hardware_class = machine_info_[kHardwareClassCrosSystemKey];
155 if (hardware_class.empty() || hardware_class == kCrosSystemUnknownValue) 179 if (hardware_class.empty() || hardware_class == kCrosSystemUnknownValue)
156 machine_info_[kHardwareClassKey] = kUnknownHardwareClass; 180 machine_info_[kHardwareClassKey] = kUnknownHardwareClass;
157 else 181 else
158 machine_info_[kHardwareClassKey] = hardware_class; 182 machine_info_[kHardwareClassKey] = hardware_class;
159 183
160 parser.GetNameValuePairsFromFile(FilePath(kMachineHardwareInfoFile), 184 parser.GetNameValuePairsFromFile(FilePath(kMachineHardwareInfoFile),
161 kMachineHardwareInfoEq, 185 kMachineHardwareInfoEq,
162 kMachineHardwareInfoDelim); 186 kMachineHardwareInfoDelim);
163 parser.GetNameValuePairsFromFile(FilePath(kEchoCouponFile), 187 parser.GetNameValuePairsFromFile(FilePath(kEchoCouponFile),
164 kEchoCouponEq, 188 kEchoCouponEq,
165 kEchoCouponDelim); 189 kEchoCouponDelim);
166 parser.GetNameValuePairsFromFile(FilePath(kMachineOSInfoFile), 190 parser.GetNameValuePairsFromFile(FilePath(kMachineOSInfoFile),
167 kMachineOSInfoEq, 191 kMachineOSInfoEq,
168 kMachineOSInfoDelim); 192 kMachineOSInfoDelim);
169 parser.GetNameValuePairsFromFile(FilePath(kVpdFile), kVpdEq, kVpdDelim); 193 parser.GetNameValuePairsFromFile(FilePath(kVpdFile), kVpdEq, kVpdDelim);
170 194
171 // Finished loading the statistics. 195 // Finished loading the statistics.
172 on_statistics_loaded_.Signal(); 196 on_statistics_loaded_.Signal();
173 VLOG(1) << "Finished loading statistics"; 197 VLOG(1) << "Finished loading statistics";
174 198
199 // Any callbacks registed before Signal() are in |callbacks_|. Any registed
200 // after Signal() will be immediately posted. NotifyOnUI() posts the callbacks
201 // in |callbacks_| from the UI loop.
202 std::vector<base::Closure>* callbacks = new std::vector<base::Closure>();
203 callbacks->swap(callbacks_);
jar (doing other things) 2012/04/24 18:37:40 What thread are you running on? Are you ensured t
Joao da Silva 2012/04/27 09:47:48 This happens in the blocking pool, but the callbac
jar (doing other things) 2012/04/27 18:00:38 It appears as though the line: callbacks_.push_ba
Joao da Silva 2012/05/15 13:52:47 You're totally right. I tried to make this a stati
204 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
205 base::Bind(NotifyOnUI, base::Owned(callbacks)));
206
175 #if defined(GOOGLE_CHROME_BUILD) 207 #if defined(GOOGLE_CHROME_BUILD)
176 // TODO(kochi): This is for providing a channel information to 208 // TODO(kochi): This is for providing a channel information to
177 // chrome::VersionInfo::GetChannel()/GetVersionStringModifier(), 209 // chrome::VersionInfo::GetChannel()/GetVersionStringModifier(),
178 // but this is still late for some early customers such as 210 // but this is still late for some early customers such as
179 // prerender::ConfigurePrefetchAndPrerender() and 211 // prerender::ConfigurePrefetchAndPrerender() and
180 // ThreadWatcherList::ParseCommandLine(). 212 // ThreadWatcherList::ParseCommandLine().
181 // See http://crbug.com/107333 . 213 // See http://crbug.com/107333 .
182 const char kChromeOSReleaseTrack[] = "CHROMEOS_RELEASE_TRACK"; 214 const char kChromeOSReleaseTrack[] = "CHROMEOS_RELEASE_TRACK";
183 std::string channel; 215 std::string channel;
184 if (GetMachineStatistic(kChromeOSReleaseTrack, &channel)) { 216 if (GetMachineStatistic(kChromeOSReleaseTrack, &channel)) {
(...skipping 18 matching lines...) Expand all
203 235
204 // The stub StatisticsProvider implementation used on Linux desktop. 236 // The stub StatisticsProvider implementation used on Linux desktop.
205 class StatisticsProviderStubImpl : public StatisticsProvider { 237 class StatisticsProviderStubImpl : public StatisticsProvider {
206 public: 238 public:
207 // StatisticsProvider implementation: 239 // StatisticsProvider implementation:
208 virtual bool GetMachineStatistic(const std::string& name, 240 virtual bool GetMachineStatistic(const std::string& name,
209 std::string* result) OVERRIDE { 241 std::string* result) OVERRIDE {
210 return false; 242 return false;
211 } 243 }
212 244
245 virtual void WhenReady(const base::Closure& callback) OVERRIDE {
246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
247 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
248 }
249
213 static StatisticsProviderStubImpl* GetInstance() { 250 static StatisticsProviderStubImpl* GetInstance() {
214 return Singleton<StatisticsProviderStubImpl, 251 return Singleton<StatisticsProviderStubImpl,
215 DefaultSingletonTraits<StatisticsProviderStubImpl> >::get(); 252 DefaultSingletonTraits<StatisticsProviderStubImpl> >::get();
216 } 253 }
217 254
218 private: 255 private:
219 friend struct DefaultSingletonTraits<StatisticsProviderStubImpl>; 256 friend struct DefaultSingletonTraits<StatisticsProviderStubImpl>;
220 257
221 StatisticsProviderStubImpl() { 258 StatisticsProviderStubImpl() {
222 } 259 }
223 260
224 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderStubImpl); 261 DISALLOW_COPY_AND_ASSIGN(StatisticsProviderStubImpl);
225 }; 262 };
226 263
227 StatisticsProvider* StatisticsProvider::GetInstance() { 264 StatisticsProvider* StatisticsProvider::GetInstance() {
228 if (base::chromeos::IsRunningOnChromeOS()) { 265 if (base::chromeos::IsRunningOnChromeOS()) {
229 return StatisticsProviderImpl::GetInstance(); 266 return StatisticsProviderImpl::GetInstance();
230 } else { 267 } else {
231 return StatisticsProviderStubImpl::GetInstance(); 268 return StatisticsProviderStubImpl::GetInstance();
232 } 269 }
233 } 270 }
234 271
235 } // namespace system 272 } // namespace system
236 } // namespace chromeos 273 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698