OLD | NEW |
| (Empty) |
1 // Copyright 2008-2010 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 | |
16 | |
17 #include "omaha/common/stats_uploader.h" | |
18 #include <atlbase.h> | |
19 #include <atlconv.h> | |
20 #include <atlstr.h> | |
21 #include <ctime> | |
22 #include "omaha/base/const_object_names.h" | |
23 #include "omaha/base/constants.h" | |
24 #include "omaha/base/debug.h" | |
25 #include "omaha/base/error.h" | |
26 #include "omaha/base/logging.h" | |
27 #include "omaha/base/omaha_version.h" | |
28 #include "omaha/base/safe_format.h" | |
29 #include "omaha/base/scoped_impersonation.h" | |
30 #include "omaha/base/synchronized.h" | |
31 #include "omaha/base/reg_key.h" | |
32 #include "omaha/base/utils.h" | |
33 #include "omaha/base/vista_utils.h" | |
34 #include "omaha/common/config_manager.h" | |
35 #include "omaha/common/goopdate_utils.h" | |
36 #include "omaha/net/network_config.h" | |
37 #include "omaha/net/network_request.h" | |
38 #include "omaha/net/simple_request.h" | |
39 #include "omaha/statsreport/aggregator-win32.h" | |
40 #include "omaha/statsreport/const-win32.h" | |
41 #include "omaha/statsreport/formatter.h" | |
42 #include "omaha/statsreport/metrics.h" | |
43 #include "omaha/statsreport/persistent_iterator-win32.h" | |
44 | |
45 using stats_report::g_global_metrics; | |
46 | |
47 using stats_report::kCountsKeyName; | |
48 using stats_report::kTimingsKeyName; | |
49 using stats_report::kIntegersKeyName; | |
50 using stats_report::kBooleansKeyName; | |
51 using stats_report::kStatsKeyFormatString; | |
52 using stats_report::kLastTransmissionTimeValueName; | |
53 | |
54 using stats_report::Formatter; | |
55 using stats_report::MetricsAggregatorWin32; | |
56 using stats_report::PersistentMetricsIteratorWin32; | |
57 | |
58 namespace omaha { | |
59 | |
60 namespace { | |
61 | |
62 HRESULT ResetPersistentMetrics(RegKey* key) { | |
63 ASSERT1(key); | |
64 HRESULT result = S_OK; | |
65 DWORD now_sec = static_cast<DWORD>(time(NULL)); | |
66 HRESULT hr = key->SetValue(kLastTransmissionTimeValueName, now_sec); | |
67 if (FAILED(hr)) { | |
68 result = hr; | |
69 } | |
70 hr = key->DeleteSubKey(kCountsKeyName); | |
71 if (FAILED(hr)) { | |
72 result = hr; | |
73 } | |
74 hr = key->DeleteSubKey(kTimingsKeyName); | |
75 if (FAILED(hr)) { | |
76 result = hr; | |
77 } | |
78 hr = key->DeleteSubKey(kIntegersKeyName); | |
79 if (FAILED(hr)) { | |
80 result = hr; | |
81 } | |
82 hr = key->DeleteSubKey(kBooleansKeyName); | |
83 if (FAILED(hr)) { | |
84 result = hr; | |
85 } | |
86 return result; | |
87 } | |
88 | |
89 // Returns S_OK without uploading in OEM mode. | |
90 HRESULT UploadMetrics(bool is_machine, | |
91 const TCHAR* extra_url_data, | |
92 const TCHAR* content) { | |
93 ASSERT1(content); | |
94 | |
95 CString uid = goopdate_utils::GetUserIdLazyInit(is_machine); | |
96 | |
97 // Impersonate the user if the caller is machine, running as local system, | |
98 // and a user is logged on to the system. | |
99 scoped_handle impersonation_token( | |
100 goopdate_utils::GetImpersonationTokenForMachineProcess(is_machine)); | |
101 scoped_impersonation impersonate_user(get(impersonation_token)); | |
102 | |
103 // Do not access the network during an OEM install. | |
104 if (!ConfigManager::Instance()->CanUseNetwork(is_machine)) { | |
105 CORE_LOG(L1, (_T("[Stats not uploaded because network use prohibited]"))); | |
106 return GOOPDATE_E_CANNOT_USE_NETWORK; | |
107 } | |
108 | |
109 const TCHAR* version = GetVersionString(); | |
110 CString test_source(ConfigManager::Instance()->GetTestSource()); | |
111 | |
112 CString url; | |
113 HRESULT hr = ConfigManager::Instance()->GetUsageStatsReportUrl(&url); | |
114 if (FAILED(hr)) { | |
115 CORE_LOG(LE, (_T("[GetUsageStatsReportUrl failed][0x%08x]"), hr)); | |
116 return hr; | |
117 } | |
118 SafeCStringAppendFormat(&url, _T("?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s"), | |
119 kMetricsServerParamSourceId, kMetricsProductName, | |
120 kMetricsServerParamVersion, version, | |
121 kMetricsServerParamIsMachine, is_machine ? _T("1") : _T("0"), | |
122 kMetricsServerTestSource, test_source, | |
123 kMetricsServerUserId, uid, | |
124 extra_url_data); | |
125 | |
126 CORE_LOG(L3, (_T("[upload usage stats][%s]"), content)); | |
127 | |
128 NetworkConfig* network_config = NULL; | |
129 NetworkConfigManager& network_manager = NetworkConfigManager::Instance(); | |
130 hr = network_manager.GetUserNetworkConfig(&network_config); | |
131 if (FAILED(hr)) { | |
132 CORE_LOG(LE, (_T("[GetUserNetworkConfig failed][0x%08x]"), hr)); | |
133 return hr; | |
134 } | |
135 NetworkRequest network_request(network_config->session()); | |
136 | |
137 network_request.set_num_retries(1); | |
138 network_request.AddHttpRequest(new SimpleRequest); | |
139 | |
140 // PostRequest falls back to https. | |
141 std::vector<uint8> response_buffer; | |
142 return PostRequest(&network_request, true, url, content, &response_buffer); | |
143 } | |
144 | |
145 HRESULT ReportMetrics(bool is_machine, | |
146 const TCHAR* extra_url_data, | |
147 DWORD interval) { | |
148 PersistentMetricsIteratorWin32 it(kMetricsProductName, is_machine), end; | |
149 Formatter formatter(CT2A(kMetricsProductName), interval); | |
150 | |
151 for (; it != end; ++it) { | |
152 formatter.AddMetric(*it); | |
153 } | |
154 | |
155 return UploadMetrics(is_machine, extra_url_data, CA2T(formatter.output())); | |
156 } | |
157 | |
158 HRESULT DoResetMetrics(bool is_machine) { | |
159 CString key_name; | |
160 key_name.Format(kStatsKeyFormatString, kMetricsProductName); | |
161 HKEY parent_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
162 RegKey key; | |
163 HRESULT hr = key.Create(parent_key, key_name); | |
164 if (FAILED(hr)) { | |
165 CORE_LOG(LE, (_T("[Unable to create metrics key][0x%08x]"), hr)); | |
166 return hr; | |
167 } | |
168 return ResetPersistentMetrics(&key); | |
169 } | |
170 | |
171 HRESULT DoAggregateMetrics(bool is_machine) { | |
172 MetricsAggregatorWin32 aggregator(g_global_metrics, | |
173 kMetricsProductName, | |
174 is_machine); | |
175 if (!aggregator.AggregateMetrics()) { | |
176 CORE_LOG(LW, (_T("[Metrics aggregation failed for unknown reasons]"))); | |
177 return GOOPDATE_E_METRICS_AGGREGATE_FAILED; | |
178 } | |
179 return S_OK; | |
180 } | |
181 | |
182 HRESULT DoAggregateAndReportMetrics(bool is_machine, bool force_report) { | |
183 CString key_name; | |
184 key_name.Format(kStatsKeyFormatString, kMetricsProductName); | |
185 HKEY parent_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
186 RegKey key; | |
187 HRESULT hr = key.Create(parent_key, key_name); | |
188 if (FAILED(hr)) { | |
189 CORE_LOG(LE, (_T("[Unable to create metrics key][0x%08x]"), hr)); | |
190 return hr; | |
191 } | |
192 | |
193 DWORD now_sec = static_cast<DWORD>(time(NULL)); | |
194 | |
195 DWORD last_transmission_sec(0); | |
196 hr = key.GetValue(kLastTransmissionTimeValueName, &last_transmission_sec); | |
197 | |
198 // Reset and start over if last transmission time is missing or hinky. | |
199 if (FAILED(hr) || last_transmission_sec > now_sec) { | |
200 CORE_LOG(LW, (_T("[hinky or missing last transmission time][%u][now: %u]"), | |
201 last_transmission_sec, now_sec)); | |
202 ResetPersistentMetrics(&key); | |
203 return S_OK; | |
204 } | |
205 | |
206 hr = DoAggregateMetrics(is_machine); | |
207 if (FAILED(hr)) { | |
208 CORE_LOG(LE, (_T("[DoAggregateMetrics failed][0x%08x]"), hr)); | |
209 return hr; | |
210 } | |
211 | |
212 DWORD time_since_last_transmission = now_sec - last_transmission_sec; | |
213 if (!force_report && | |
214 time_since_last_transmission < kMetricsUploadIntervalSec) { | |
215 CORE_LOG(L1, (_T("[Stats upload not needed][last: %u][now: %u]"), | |
216 last_transmission_sec, now_sec)); | |
217 return S_OK; | |
218 } | |
219 | |
220 // Report the metrics, reset the metrics, and update 'LastTransmission'. | |
221 hr = ReportMetrics(is_machine, NULL, time_since_last_transmission); | |
222 if (FAILED(hr)) { | |
223 CORE_LOG(LE, (_T("[Stats upload failed][0x%08x]"), hr)); | |
224 return hr; | |
225 } | |
226 | |
227 VERIFY1(SUCCEEDED(ResetPersistentMetrics(&key))); | |
228 CORE_LOG(L3, (_T("[Stats upload successful]"))); | |
229 return S_OK; | |
230 } | |
231 | |
232 bool InitializeLock(GLock* lock, bool is_machine) { | |
233 ASSERT1(lock); | |
234 NamedObjectAttributes attributes; | |
235 GetNamedObjectAttributes(kMetricsSerializer, is_machine, &attributes); | |
236 return lock->InitializeWithSecAttr(attributes.name, &attributes.sa); | |
237 } | |
238 | |
239 } // namespace | |
240 | |
241 | |
242 HRESULT ResetMetrics(bool is_machine) { | |
243 CORE_LOG(L2, (_T("[ResetMetrics]"))); | |
244 GLock lock; | |
245 if (!InitializeLock(&lock, is_machine)) { | |
246 return GOOPDATE_E_METRICS_LOCK_INIT_FAILED; | |
247 } | |
248 __mutexScope(lock); | |
249 return DoResetMetrics(is_machine); | |
250 } | |
251 | |
252 HRESULT AggregateMetrics(bool is_machine) { | |
253 CORE_LOG(L2, (_T("[AggregateMetrics]"))); | |
254 | |
255 if (!ConfigManager::Instance()->CanCollectStats(is_machine)) { | |
256 return S_OK; | |
257 } | |
258 | |
259 GLock lock; | |
260 if (!InitializeLock(&lock, is_machine)) { | |
261 return GOOPDATE_E_METRICS_LOCK_INIT_FAILED; | |
262 } | |
263 __mutexScope(lock); | |
264 return DoAggregateMetrics(is_machine); | |
265 } | |
266 | |
267 HRESULT AggregateAndReportMetrics(bool is_machine, bool force_report) { | |
268 CORE_LOG(L2, (_T("[AggregateAndReportMetrics]"))); | |
269 | |
270 if (!ConfigManager::Instance()->CanCollectStats(is_machine)) { | |
271 return S_OK; | |
272 } | |
273 | |
274 GLock lock; | |
275 if (!InitializeLock(&lock, is_machine)) { | |
276 return GOOPDATE_E_METRICS_LOCK_INIT_FAILED; | |
277 } | |
278 __mutexScope(lock); | |
279 return DoAggregateAndReportMetrics(is_machine, force_report); | |
280 } | |
281 | |
282 } // namespace omaha | |
283 | |
OLD | NEW |