Index: chrome_frame/metrics_service.cc |
diff --git a/chrome_frame/metrics_service.cc b/chrome_frame/metrics_service.cc |
deleted file mode 100644 |
index da7cffd813ad11e53b4064106655b14999bf541e..0000000000000000000000000000000000000000 |
--- a/chrome_frame/metrics_service.cc |
+++ /dev/null |
@@ -1,464 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-//------------------------------------------------------------------------------ |
-// Description of the life cycle of a instance of MetricsService. |
-// |
-// OVERVIEW |
-// |
-// A MetricsService instance is created at ChromeFrame startup in |
-// the IE process. It is the central controller for the UMA log data. |
-// Its major job is to manage logs, prepare them for transmission. |
-// Currently only histogram data is tracked in log. When MetricsService |
-// prepares log for submission it snapshots the current stats of histograms, |
-// translates log to a protocol buffer. Transmission includes submitting a |
-// compressed log as data in a URL-get, and is performed using functionality |
-// provided by Urlmon |
-// The actual transmission is performed using a windows timer procedure which |
-// basically means that the thread on which the MetricsService object is |
-// instantiated needs a message pump. Also on IE7 where every tab is created |
-// on its own thread we would have a case where the timer procedures can |
-// compete for sending histograms. |
-// |
-// When preparing log for submission we acquire a list of all local histograms |
-// that have been flagged for upload to the UMA server. |
-// |
-// When ChromeFrame shuts down, there will typically be a fragment of an ongoing |
-// log that has not yet been transmitted. Currently this data is ignored. |
-// |
-// With the above overview, we can now describe the state machine's various |
-// stats, based on the State enum specified in the state_ member. Those states |
-// are: |
-// |
-// INITIALIZED, // Constructor was called. |
-// ACTIVE, // Accumalating log data. |
-// STOPPED, // Service has stopped. |
-// |
-//----------------------------------------------------------------------------- |
- |
-#include "chrome_frame/metrics_service.h" |
- |
-#include <atlbase.h> |
-#include <atlwin.h> |
-#include <objbase.h> |
-#include <windows.h> |
- |
-#include "base/metrics/statistics_recorder.h" |
-#include "base/strings/string16.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/stringprintf.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "base/synchronization/lock.h" |
-#include "base/win/scoped_comptr.h" |
-#include "chrome/common/chrome_version_info.h" |
-#include "chrome/common/metrics/metrics_log_base.h" |
-#include "chrome/common/metrics/metrics_log_manager.h" |
-#include "chrome/installer/util/browser_distribution.h" |
-#include "chrome/installer/util/google_update_settings.h" |
-#include "chrome_frame/bind_status_callback_impl.h" |
-#include "chrome_frame/crash_reporting/crash_metrics.h" |
-#include "chrome_frame/html_utils.h" |
-#include "chrome_frame/utils.h" |
- |
-using base::Time; |
-using base::TimeDelta; |
-using base::win::ScopedComPtr; |
- |
-// The first UMA upload occurs after this interval. |
-static const int kInitialUMAUploadTimeoutMilliSeconds = 30000; |
- |
-// Default to one UMA upload per 10 mins. |
-static const int kMinMilliSecondsPerUMAUpload = 600000; |
- |
-base::LazyInstance<base::ThreadLocalPointer<MetricsService> > |
- MetricsService::g_metrics_instance_ = LAZY_INSTANCE_INITIALIZER; |
- |
-std::string MetricsService::client_id_; |
- |
-base::Lock MetricsService::metrics_service_lock_; |
- |
-// This class provides functionality to upload the ChromeFrame UMA data to the |
-// server. An instance of this class is created whenever we have data to be |
-// uploaded to the server. |
-class ChromeFrameMetricsDataUploader : public BSCBImpl { |
- public: |
- ChromeFrameMetricsDataUploader() |
- : cache_stream_(NULL), |
- upload_data_size_(0) { |
- DVLOG(1) << __FUNCTION__; |
- } |
- |
- ~ChromeFrameMetricsDataUploader() { |
- DVLOG(1) << __FUNCTION__; |
- } |
- |
- static HRESULT UploadDataHelper( |
- const std::string& upload_data, |
- const std::string& server_url, |
- const std::string& mime_type) { |
- CComObject<ChromeFrameMetricsDataUploader>* data_uploader = NULL; |
- CComObject<ChromeFrameMetricsDataUploader>::CreateInstance(&data_uploader); |
- DCHECK(data_uploader != NULL); |
- |
- data_uploader->AddRef(); |
- HRESULT hr = data_uploader->UploadData(upload_data, server_url, mime_type); |
- if (FAILED(hr)) { |
- DLOG(ERROR) << "Failed to initialize ChromeFrame UMA data uploader: Err" |
- << hr; |
- } |
- data_uploader->Release(); |
- return hr; |
- } |
- |
- HRESULT UploadData(const std::string& upload_data, |
- const std::string& server_url, |
- const std::string& mime_type) { |
- if (upload_data.empty()) { |
- NOTREACHED() << "Invalid upload data"; |
- return E_INVALIDARG; |
- } |
- |
- DCHECK(cache_stream_.get() == NULL); |
- |
- upload_data_size_ = upload_data.size() + 1; |
- |
- HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, cache_stream_.Receive()); |
- if (FAILED(hr)) { |
- NOTREACHED() << "Failed to create stream. Error:" |
- << hr; |
- return hr; |
- } |
- |
- DCHECK(cache_stream_.get()); |
- |
- unsigned long written = 0; |
- cache_stream_->Write(upload_data.c_str(), upload_data_size_, &written); |
- DCHECK(written == upload_data_size_); |
- |
- RewindStream(cache_stream_); |
- |
- server_url_ = base::ASCIIToWide(server_url); |
- mime_type_ = mime_type; |
- DCHECK(!server_url_.empty()); |
- DCHECK(!mime_type_.empty()); |
- |
- hr = CreateURLMoniker(NULL, server_url_.c_str(), |
- upload_moniker_.Receive()); |
- if (FAILED(hr)) { |
- DLOG(ERROR) << "Failed to create url moniker for url:" |
- << server_url_.c_str() |
- << " Error:" |
- << hr; |
- } else { |
- ScopedComPtr<IBindCtx> context; |
- hr = CreateAsyncBindCtx(0, this, NULL, context.Receive()); |
- DCHECK(SUCCEEDED(hr)); |
- DCHECK(context); |
- |
- ScopedComPtr<IStream> stream; |
- hr = upload_moniker_->BindToStorage( |
- context, NULL, IID_IStream, |
- reinterpret_cast<void**>(stream.Receive())); |
- if (FAILED(hr)) { |
- NOTREACHED(); |
- DLOG(ERROR) << "Failed to bind to upload data moniker. Error:" |
- << hr; |
- } |
- } |
- return hr; |
- } |
- |
- STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, DWORD reserved, |
- LPWSTR* additional_headers) { |
- std::string new_headers; |
- new_headers = |
- base::StringPrintf( |
- "Content-Length: %s\r\n" |
- "Content-Type: %s\r\n" |
- "%s\r\n", |
- base::Int64ToString(upload_data_size_).c_str(), |
- mime_type_.c_str(), |
- http_utils::GetDefaultUserAgentHeaderWithCFTag().c_str()); |
- |
- *additional_headers = reinterpret_cast<wchar_t*>( |
- CoTaskMemAlloc((new_headers.size() + 1) * sizeof(wchar_t))); |
- |
- lstrcpynW(*additional_headers, base::ASCIIToWide(new_headers).c_str(), |
- new_headers.size()); |
- |
- return BSCBImpl::BeginningTransaction(url, headers, reserved, |
- additional_headers); |
- } |
- |
- STDMETHOD(GetBindInfo)(DWORD* bind_flags, BINDINFO* bind_info) { |
- if ((bind_info == NULL) || (bind_info->cbSize == 0) || |
- (bind_flags == NULL)) |
- return E_INVALIDARG; |
- |
- *bind_flags = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; |
- // Bypass caching proxies on POSTs and PUTs and avoid writing responses to |
- // these requests to the browser's cache |
- *bind_flags |= BINDF_GETNEWESTVERSION | BINDF_PRAGMA_NO_CACHE; |
- |
- DCHECK(cache_stream_.get()); |
- |
- // Initialize the STGMEDIUM. |
- memset(&bind_info->stgmedData, 0, sizeof(STGMEDIUM)); |
- bind_info->grfBindInfoF = 0; |
- bind_info->szCustomVerb = NULL; |
- bind_info->dwBindVerb = BINDVERB_POST; |
- bind_info->stgmedData.tymed = TYMED_ISTREAM; |
- bind_info->stgmedData.pstm = cache_stream_.get(); |
- bind_info->stgmedData.pstm->AddRef(); |
- return BSCBImpl::GetBindInfo(bind_flags, bind_info); |
- } |
- |
- STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_headers, |
- LPCWSTR request_headers, LPWSTR* additional_headers) { |
- DVLOG(1) << __FUNCTION__ << " headers: \n" << response_headers; |
- return BSCBImpl::OnResponse(response_code, response_headers, |
- request_headers, additional_headers); |
- } |
- |
- private: |
- std::wstring server_url_; |
- std::string mime_type_; |
- size_t upload_data_size_; |
- ScopedComPtr<IStream> cache_stream_; |
- ScopedComPtr<IMoniker> upload_moniker_; |
-}; |
- |
-MetricsService* MetricsService::GetInstance() { |
- if (g_metrics_instance_.Pointer()->Get()) |
- return g_metrics_instance_.Pointer()->Get(); |
- |
- g_metrics_instance_.Pointer()->Set(new MetricsService); |
- return g_metrics_instance_.Pointer()->Get(); |
-} |
- |
-MetricsService::MetricsService() |
- : recording_active_(false), |
- reporting_active_(false), |
- user_permits_upload_(false), |
- state_(INITIALIZED), |
- thread_(NULL), |
- initial_uma_upload_(true), |
- transmission_timer_id_(0) { |
-} |
- |
-MetricsService::~MetricsService() { |
- SetRecording(false); |
-} |
- |
-void MetricsService::InitializeMetricsState() { |
- DCHECK(state_ == INITIALIZED); |
- |
- thread_ = base::PlatformThread::CurrentId(); |
- |
- user_permits_upload_ = GoogleUpdateSettings::GetCollectStatsConsent(); |
- // Update session ID |
- session_id_ = CrashMetricsReporter::GetInstance()->IncrementMetric( |
- CrashMetricsReporter::SESSION_ID); |
- |
- base::StatisticsRecorder::Initialize(); |
- CrashMetricsReporter::GetInstance()->set_active(true); |
-} |
- |
-// static |
-void MetricsService::Start() { |
- base::AutoLock lock(metrics_service_lock_); |
- |
- if (GetInstance()->state_ == ACTIVE) |
- return; |
- |
- GetInstance()->InitializeMetricsState(); |
- GetInstance()->SetRecording(true); |
- GetInstance()->SetReporting(true); |
-} |
- |
-// static |
-void MetricsService::Stop() { |
- base::AutoLock lock(metrics_service_lock_); |
- |
- GetInstance()->SetReporting(false); |
- GetInstance()->SetRecording(false); |
-} |
- |
-void MetricsService::SetRecording(bool enabled) { |
- DCHECK_EQ(thread_, base::PlatformThread::CurrentId()); |
- if (enabled == recording_active_) |
- return; |
- |
- if (enabled) { |
- StartRecording(); |
- } else { |
- state_ = STOPPED; |
- } |
- recording_active_ = enabled; |
-} |
- |
-// static |
-const std::string& MetricsService::GetClientID() { |
- // TODO(robertshield): Chrome Frame shouldn't generate a new ID on every run |
- // as this apparently breaks some assumptions during metric analysis. |
- // See http://crbug.com/117188 |
- if (client_id_.empty()) { |
- const int kGUIDSize = 39; |
- |
- GUID guid; |
- HRESULT guid_result = CoCreateGuid(&guid); |
- DCHECK(SUCCEEDED(guid_result)); |
- |
- base::string16 guid_string; |
- int result = StringFromGUID2(guid, |
- WriteInto(&guid_string, kGUIDSize), kGUIDSize); |
- DCHECK(result == kGUIDSize); |
- client_id_ = |
- base::WideToUTF8(guid_string.substr(1, guid_string.length() - 2)); |
- } |
- return client_id_; |
-} |
- |
-// static |
-void CALLBACK MetricsService::TransmissionTimerProc(HWND window, |
- unsigned int message, |
- unsigned int event_id, |
- unsigned int time) { |
- DVLOG(1) << "Transmission timer notified"; |
- DCHECK(GetInstance() != NULL); |
- GetInstance()->UploadData(); |
- if (GetInstance()->initial_uma_upload_) { |
- // If this is the first uma upload by this process then subsequent uma |
- // uploads should occur once every 10 minutes(default). |
- GetInstance()->initial_uma_upload_ = false; |
- DCHECK(GetInstance()->transmission_timer_id_ != 0); |
- SetTimer(NULL, GetInstance()->transmission_timer_id_, |
- kMinMilliSecondsPerUMAUpload, |
- reinterpret_cast<TIMERPROC>(TransmissionTimerProc)); |
- } |
-} |
- |
-void MetricsService::SetReporting(bool enable) { |
- static const int kChromeFrameMetricsTimerId = 0xFFFFFFFF; |
- |
- DCHECK_EQ(thread_, base::PlatformThread::CurrentId()); |
- if (reporting_active_ != enable) { |
- reporting_active_ = enable; |
- if (reporting_active_) { |
- transmission_timer_id_ = |
- SetTimer(NULL, kChromeFrameMetricsTimerId, |
- kInitialUMAUploadTimeoutMilliSeconds, |
- reinterpret_cast<TIMERPROC>(TransmissionTimerProc)); |
- } else { |
- UploadData(); |
- } |
- } |
-} |
- |
-//------------------------------------------------------------------------------ |
-// Recording control methods |
- |
-void MetricsService::StartRecording() { |
- DCHECK_EQ(thread_, base::PlatformThread::CurrentId()); |
- if (log_manager_.current_log()) |
- return; |
- |
- MetricsLogBase::LogType log_type = (state_ == INITIALIZED) ? |
- MetricsLogBase::INITIAL_LOG : MetricsLogBase::ONGOING_LOG; |
- log_manager_.BeginLoggingWithLog(new MetricsLogBase(GetClientID(), |
- session_id_, |
- GetVersionString()), |
- log_type); |
- if (state_ == INITIALIZED) |
- state_ = ACTIVE; |
-} |
- |
-void MetricsService::StopRecording(bool save_log) { |
- DCHECK_EQ(thread_, base::PlatformThread::CurrentId()); |
- if (!log_manager_.current_log()) |
- return; |
- |
- // Put incremental histogram deltas at the end of all log transmissions. |
- // Don't bother if we're going to discard current_log. |
- if (save_log) { |
- CrashMetricsReporter::GetInstance()->RecordCrashMetrics(); |
- RecordCurrentHistograms(); |
- } |
- |
- if (save_log) { |
- log_manager_.FinishCurrentLog(); |
- log_manager_.StageNextLogForUpload(); |
- } else { |
- log_manager_.DiscardCurrentLog(); |
- } |
-} |
- |
-void MetricsService::MakePendingLog() { |
- DCHECK_EQ(thread_, base::PlatformThread::CurrentId()); |
- if (log_manager_.has_staged_log()) |
- return; |
- |
- if (state_ != ACTIVE) { |
- NOTREACHED(); |
- return; |
- } |
- |
- StopRecording(true); |
- StartRecording(); |
-} |
- |
-bool MetricsService::TransmissionPermitted() const { |
- // If the user forbids uploading that's their business, and we don't upload |
- // anything. |
- return user_permits_upload_; |
-} |
- |
-bool MetricsService::UploadData() { |
- DCHECK_EQ(thread_, base::PlatformThread::CurrentId()); |
- |
- if (!GetInstance()->TransmissionPermitted()) |
- return false; |
- |
- static long currently_uploading = 0; |
- if (InterlockedCompareExchange(¤tly_uploading, 1, 0)) { |
- DVLOG(1) << "Contention for uploading metrics data. Backing off"; |
- return false; |
- } |
- |
- MakePendingLog(); |
- |
- bool ret = true; |
- |
- if (log_manager_.has_staged_log()) { |
- HRESULT hr = ChromeFrameMetricsDataUploader::UploadDataHelper( |
- log_manager_.staged_log_text(), kServerUrl, kMimeType); |
- DCHECK(SUCCEEDED(hr)); |
- log_manager_.DiscardStagedLog(); |
- } else { |
- NOTREACHED(); |
- ret = false; |
- } |
- |
- currently_uploading = 0; |
- return ret; |
-} |
- |
-// static |
-std::string MetricsService::GetVersionString() { |
- chrome::VersionInfo version_info; |
- if (version_info.is_valid()) { |
- std::string version = version_info.Version(); |
- // Add the -F extensions to ensure that UMA data uploaded by ChromeFrame |
- // lands in the ChromeFrame bucket. |
- version += "-F"; |
- if (!version_info.IsOfficialBuild()) |
- version.append("-devel"); |
- return version; |
- } else { |
- NOTREACHED() << "Unable to retrieve version string."; |
- } |
- |
- return std::string(); |
-} |