| 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 |