| Index: chrome_frame/metrics_service.cc
|
| ===================================================================
|
| --- chrome_frame/metrics_service.cc (revision 81938)
|
| +++ chrome_frame/metrics_service.cc (working copy)
|
| @@ -44,47 +44,29 @@
|
| #include <objbase.h>
|
| #include <windows.h>
|
|
|
| -#include <vector>
|
| -
|
| #if defined(USE_SYSTEM_LIBBZ2)
|
| #include <bzlib.h>
|
| #else
|
| #include "third_party/bzip2/bzlib.h"
|
| #endif
|
|
|
| -#include "base/file_version_info.h"
|
| -#include "base/string_split.h"
|
| #include "base/string_util.h"
|
| #include "base/stringprintf.h"
|
| #include "base/synchronization/lock.h"
|
| #include "base/string_number_conversions.h"
|
| -#include "base/threading/thread.h"
|
| #include "base/utf_string_conversions.h"
|
| +#include "base/win/scoped_comptr.h"
|
| #include "chrome/common/chrome_version_info.h"
|
| -#include "chrome/common/net/url_fetcher.h"
|
| #include "chrome/installer/util/browser_distribution.h"
|
| -#include "chrome/installer/util/chrome_frame_distribution.h"
|
| #include "chrome/installer/util/google_update_settings.h"
|
| #include "chrome_frame/bind_status_callback_impl.h"
|
| -#include "chrome_frame/chrome_frame_delegate.h"
|
| #include "chrome_frame/crash_reporting/crash_metrics.h"
|
| #include "chrome_frame/html_utils.h"
|
| -#include "chrome_frame/http_negotiate.h"
|
| #include "chrome_frame/utils.h"
|
| -#include "net/base/capturing_net_log.h"
|
| -#include "net/base/cert_verifier.h"
|
| -#include "net/base/host_resolver.h"
|
| -#include "net/base/ssl_config_service_defaults.h"
|
| -#include "net/base/upload_data.h"
|
| -#include "net/http/http_auth_handler_factory.h"
|
| -#include "net/http/http_cache.h"
|
| -#include "net/http/http_network_session.h"
|
| -#include "net/url_request/url_request_context.h"
|
| -#include "net/url_request/url_request_context_getter.h"
|
| -#include "net/url_request/url_request_status.h"
|
|
|
| using base::Time;
|
| using base::TimeDelta;
|
| +using base::win::ScopedComPtr;
|
|
|
| static const char kMetricsType[] = "application/vnd.mozilla.metrics.bz2";
|
|
|
| @@ -94,269 +76,164 @@
|
| // Default to one UMA upload per 10 mins.
|
| static const int kMinMilliSecondsPerUMAUpload = 600000;
|
|
|
| -base::LazyInstance<MetricsService>
|
| - g_metrics_instance_(base::LINKER_INITIALIZED);
|
| +base::LazyInstance<base::ThreadLocalPointer<MetricsService> >
|
| + MetricsService::g_metrics_instance_(base::LINKER_INITIALIZED);
|
|
|
| base::Lock MetricsService::metrics_service_lock_;
|
|
|
| -// Traits to create an instance of the ChromeFrame upload thread.
|
| -struct UploadThreadInstanceTraits
|
| - : public base::LeakyLazyInstanceTraits<base::Thread> {
|
| - static base::Thread* New(void* instance) {
|
| - // Use placement new to initialize our instance in our preallocated space.
|
| - // The parenthesis is very important here to force POD type initialization.
|
| - base::Thread* upload_thread =
|
| - new(instance) base::Thread("ChromeFrameUploadThread");
|
| - base::Thread::Options options;
|
| - options.message_loop_type = MessageLoop::TYPE_IO;
|
| - bool ret = upload_thread->StartWithOptions(options);
|
| - if (!ret) {
|
| - NOTREACHED() << "Failed to start upload thread";
|
| - }
|
| - return upload_thread;
|
| - }
|
| -};
|
| -
|
| -// ChromeFrame UMA uploads occur on this thread. This thread is started on the
|
| -// IE UI thread. This thread needs to be stopped on the same thread it was
|
| -// started on. We don't have a good way of achieving this at this point. This
|
| -// thread object is currently leaked.
|
| -// TODO(ananta)
|
| -// TODO(vitalybuka@chromium.org) : Fix this by using MetricsService::Stop() in
|
| -// appropriate location.
|
| -base::LazyInstance<base::Thread, UploadThreadInstanceTraits>
|
| - g_metrics_upload_thread_(base::LINKER_INITIALIZED);
|
| -
|
| -base::Lock g_metrics_service_lock;
|
| -
|
| extern base::LazyInstance<base::StatisticsRecorder> g_statistics_recorder_;
|
|
|
| -// This class provides HTTP request context information for metrics upload
|
| -// requests initiated by ChromeFrame.
|
| -class ChromeFrameUploadRequestContext : public net::URLRequestContext {
|
| +// 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:
|
| - explicit ChromeFrameUploadRequestContext(MessageLoop* io_loop)
|
| - : io_loop_(io_loop) {
|
| - Initialize();
|
| + ChromeFrameMetricsDataUploader()
|
| + : cache_stream_(NULL),
|
| + upload_data_size_(0) {
|
| + DVLOG(1) << __FUNCTION__;
|
| }
|
|
|
| - ~ChromeFrameUploadRequestContext() {
|
| + ~ChromeFrameMetricsDataUploader() {
|
| DVLOG(1) << __FUNCTION__;
|
| - delete http_transaction_factory();
|
| - delete http_auth_handler_factory();
|
| - delete cert_verifier();
|
| - delete host_resolver();
|
| }
|
|
|
| - void Initialize() {
|
| - user_agent_ = http_utils::GetDefaultUserAgent();
|
| - user_agent_ = http_utils::AddChromeFrameToUserAgentValue(
|
| - user_agent_);
|
| + static HRESULT ChromeFrameMetricsDataUploader::UploadDataHelper(
|
| + const std::string& upload_data) {
|
| + CComObject<ChromeFrameMetricsDataUploader>* data_uploader = NULL;
|
| + CComObject<ChromeFrameMetricsDataUploader>::CreateInstance(&data_uploader);
|
| + DCHECK(data_uploader != NULL);
|
|
|
| - set_host_resolver(
|
| - net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
|
| - NULL, NULL));
|
| - set_cert_verifier(new net::CertVerifier);
|
| - net::ProxyConfigService* proxy_config_service =
|
| - net::ProxyService::CreateSystemProxyConfigService(NULL, NULL);
|
| - DCHECK(proxy_config_service);
|
| -
|
| - set_proxy_service(net::ProxyService::CreateUsingSystemProxyResolver(
|
| - proxy_config_service, 0, NULL));
|
| - DCHECK(proxy_service());
|
| -
|
| - set_ssl_config_service(new net::SSLConfigServiceDefaults);
|
| -
|
| - url_security_manager_.reset(
|
| - net::URLSecurityManager::Create(NULL, NULL));
|
| -
|
| - std::string csv_auth_schemes = "basic,digest,ntlm,negotiate";
|
| - std::vector<std::string> supported_schemes;
|
| - base::SplitString(csv_auth_schemes, ',', &supported_schemes);
|
| -
|
| - set_http_auth_handler_factory(net::HttpAuthHandlerRegistryFactory::Create(
|
| - supported_schemes, url_security_manager_.get(), host_resolver(),
|
| - std::string(), false, false));
|
| -
|
| - net::HttpNetworkSession::Params session_params;
|
| - session_params.host_resolver = host_resolver();
|
| - session_params.cert_verifier = cert_verifier();
|
| - session_params.proxy_service = proxy_service();
|
| - session_params.http_auth_handler_factory =
|
| - http_auth_handler_factory();
|
| - session_params.ssl_config_service = ssl_config_service();
|
| - scoped_refptr<net::HttpNetworkSession> network_session =
|
| - new net::HttpNetworkSession(session_params);
|
| -
|
| - set_http_transaction_factory(new net::HttpCache(
|
| - network_session,
|
| - net::HttpCache::DefaultBackend::InMemory(0)));
|
| + data_uploader->AddRef();
|
| + HRESULT hr = data_uploader->UploadData(upload_data);
|
| + if (FAILED(hr)) {
|
| + DLOG(ERROR) << "Failed to initialize ChromeFrame UMA data uploader: Err"
|
| + << hr;
|
| + }
|
| + data_uploader->Release();
|
| + return hr;
|
| }
|
|
|
| - virtual const std::string& GetUserAgent(const GURL& url) const {
|
| - return user_agent_;
|
| - }
|
| + HRESULT UploadData(const std::string& upload_data) {
|
| + if (upload_data.empty()) {
|
| + NOTREACHED() << "Invalid upload data";
|
| + return E_INVALIDARG;
|
| + }
|
|
|
| - private:
|
| - std::string user_agent_;
|
| - MessageLoop* io_loop_;
|
| - scoped_ptr<net::URLSecurityManager> url_security_manager_;
|
| -};
|
| + DCHECK(cache_stream_.get() == NULL);
|
|
|
| -// This class provides an interface to retrieve the URL request context for
|
| -// metrics HTTP upload requests initiated by ChromeFrame.
|
| -class ChromeFrameUploadRequestContextGetter
|
| - : public net::URLRequestContextGetter {
|
| - public:
|
| - explicit ChromeFrameUploadRequestContextGetter(MessageLoop* io_loop)
|
| - : io_loop_(io_loop) {}
|
| + upload_data_size_ = upload_data.size() + 1;
|
|
|
| - virtual net::URLRequestContext* GetURLRequestContext() {
|
| - if (!context_)
|
| - context_ = new ChromeFrameUploadRequestContext(io_loop_);
|
| - return context_;
|
| - }
|
| -
|
| - virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const {
|
| - if (!io_message_loop_proxy_.get()) {
|
| - io_message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
|
| + HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, cache_stream_.Receive());
|
| + if (FAILED(hr)) {
|
| + NOTREACHED() << "Failed to create stream. Error:"
|
| + << hr;
|
| + return hr;
|
| }
|
| - return io_message_loop_proxy_;
|
| - }
|
|
|
| - private:
|
| - ~ChromeFrameUploadRequestContextGetter() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - }
|
| + DCHECK(cache_stream_.get());
|
|
|
| - scoped_refptr<net::URLRequestContext> context_;
|
| - mutable scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
|
| - MessageLoop* io_loop_;
|
| -};
|
| + unsigned long written = 0;
|
| + cache_stream_->Write(upload_data.c_str(), upload_data_size_, &written);
|
| + DCHECK(written == upload_data_size_);
|
|
|
| -// 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 URLFetcher::Delegate,
|
| - public base::RefCountedThreadSafe<ChromeFrameMetricsDataUploader>,
|
| - public CWindowImpl<ChromeFrameMetricsDataUploader>,
|
| - public TaskMarshallerThroughWindowsMessages<
|
| - ChromeFrameMetricsDataUploader> {
|
| - public:
|
| - BEGIN_MSG_MAP(ChromeFrameMetricsDataUploader)
|
| - CHAIN_MSG_MAP(
|
| - TaskMarshallerThroughWindowsMessages<ChromeFrameMetricsDataUploader>)
|
| - END_MSG_MAP()
|
| + RewindStream(cache_stream_);
|
|
|
| - ChromeFrameMetricsDataUploader()
|
| - : fetcher_(NULL) {
|
| - DVLOG(1) << __FUNCTION__;
|
| - creator_thread_id_ = base::PlatformThread::CurrentId();
|
| - }
|
| + BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
|
| + BrowserDistribution::CHROME_FRAME);
|
| + server_url_ = dist->GetStatsServerURL();
|
| + DCHECK(!server_url_.empty());
|
|
|
| - ~ChromeFrameMetricsDataUploader() {
|
| - DVLOG(1) << __FUNCTION__;
|
| - DCHECK(creator_thread_id_ == base::PlatformThread::CurrentId());
|
| - }
|
| + 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);
|
|
|
| - virtual void OnFinalMessage(HWND wnd) {
|
| - Release();
|
| - }
|
| -
|
| - bool Initialize() {
|
| - bool ret = false;
|
| -
|
| - if (!Create(NULL, NULL, NULL, WS_OVERLAPPEDWINDOW)) {
|
| - NOTREACHED() << "Failed to create window";
|
| - return ret;
|
| + 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;
|
| + }
|
| }
|
| - DCHECK(IsWindow());
|
| -
|
| - if (!g_metrics_upload_thread_.Get().IsRunning()) {
|
| - NOTREACHED() << "Upload thread is not running";
|
| - return ret;
|
| - }
|
| -
|
| - ret = true;
|
| - // Grab a reference to the current instance which ensures that it stays
|
| - // around until the HTTP request initiated below completes.
|
| - // Corresponding Release is in OnFinalMessage.
|
| - AddRef();
|
| - return ret;
|
| + return hr;
|
| }
|
|
|
| - bool Uninitialize() {
|
| - DestroyWindow();
|
| - return true;
|
| - }
|
| + STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, DWORD reserved,
|
| + LPWSTR* additional_headers) {
|
| + std::string new_headers;
|
| + new_headers =
|
| + StringPrintf("Content-Length: %s\r\n"
|
| + "Content-Type: %s\r\n"
|
| + "%s\r\n",
|
| + base::Int64ToString(upload_data_size_).c_str(),
|
| + kMetricsType,
|
| + http_utils::GetDefaultUserAgentHeaderWithCFTag());
|
|
|
| - static HRESULT ChromeFrameMetricsDataUploader::UploadDataHelper(
|
| - const std::string& upload_data) {
|
| - scoped_refptr<ChromeFrameMetricsDataUploader> data_uploader =
|
| - new ChromeFrameMetricsDataUploader();
|
| + *additional_headers = reinterpret_cast<wchar_t*>(
|
| + CoTaskMemAlloc((new_headers.size() + 1) * sizeof(wchar_t)));
|
|
|
| - if (!data_uploader->Initialize()) {
|
| - NOTREACHED() << "Failed to initialize ChromeFrameMetricsDataUploader";
|
| - return E_FAIL;
|
| - }
|
| + lstrcpynW(*additional_headers, ASCIIToWide(new_headers).c_str(),
|
| + new_headers.size());
|
|
|
| - MessageLoop* io_loop = g_metrics_upload_thread_.Get().message_loop();
|
| - if (!io_loop) {
|
| - NOTREACHED() << "Failed to initialize ChromeFrame UMA upload thread";
|
| - return E_FAIL;
|
| - }
|
| -
|
| - io_loop->PostTask(
|
| - FROM_HERE,
|
| - NewRunnableMethod(data_uploader.get(),
|
| - &ChromeFrameMetricsDataUploader::UploadData,
|
| - upload_data, io_loop));
|
| - return S_OK;
|
| + return BSCBImpl::BeginningTransaction(url, headers, reserved,
|
| + additional_headers);
|
| }
|
|
|
| - void UploadData(const std::string& upload_data, MessageLoop* message_loop) {
|
| - DCHECK(fetcher_ == NULL);
|
| - DCHECK(message_loop != NULL);
|
| + STDMETHOD(GetBindInfo)(DWORD* bind_flags, BINDINFO* bind_info) {
|
| + if ((bind_info == NULL) || (bind_info->cbSize == 0) ||
|
| + (bind_flags == NULL))
|
| + return E_INVALIDARG;
|
|
|
| - BrowserDistribution* dist = ChromeFrameDistribution::GetDistribution();
|
| - DCHECK(dist != NULL);
|
| + *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;
|
|
|
| - fetcher_ = new URLFetcher(GURL(WideToUTF8(dist->GetStatsServerURL())),
|
| - URLFetcher::POST, this);
|
| + DCHECK(cache_stream_.get());
|
|
|
| - fetcher_->set_request_context(new ChromeFrameUploadRequestContextGetter(
|
| - message_loop));
|
| - fetcher_->set_upload_data(kMetricsType, upload_data);
|
| - fetcher_->Start();
|
| + // 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);
|
| }
|
|
|
| - // URLFetcher::Delegate
|
| - virtual void OnURLFetchComplete(const URLFetcher* source,
|
| - const GURL& url,
|
| - const net::URLRequestStatus& status,
|
| - int response_code,
|
| - const ResponseCookies& cookies,
|
| - const std::string& data) {
|
| - DVLOG(1) << __FUNCTION__ << base::StringPrintf(
|
| - ": url : %hs, status:%d, response code: %d\n", url.spec().c_str(),
|
| - status.status(), response_code);
|
| - delete fetcher_;
|
| - fetcher_ = NULL;
|
| -
|
| - PostTask(FROM_HERE,
|
| - NewRunnableMethod(this,
|
| - &ChromeFrameMetricsDataUploader::Uninitialize));
|
| + 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:
|
| - URLFetcher* fetcher_;
|
| - base::PlatformThreadId creator_thread_id_;
|
| + std::wstring server_url_;
|
| + size_t upload_data_size_;
|
| + ScopedComPtr<IStream> cache_stream_;
|
| + ScopedComPtr<IMoniker> upload_moniker_;
|
| };
|
|
|
| MetricsService* MetricsService::GetInstance() {
|
| - base::AutoLock lock(g_metrics_service_lock);
|
| - return &g_metrics_instance_.Get();
|
| + 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()
|
| @@ -393,12 +270,6 @@
|
|
|
| // Ensure that an instance of the StatisticsRecorder object is created.
|
| g_statistics_recorder_.Get();
|
| -
|
| - if (user_permits_upload_) {
|
| - // Ensure that an instance of the metrics upload thread is created.
|
| - g_metrics_upload_thread_.Get();
|
| - }
|
| -
|
| CrashMetricsReporter::GetInstance()->set_active(true);
|
| }
|
|
|
| @@ -416,18 +287,14 @@
|
|
|
| // static
|
| void MetricsService::Stop() {
|
| - {
|
| - base::AutoLock lock(metrics_service_lock_);
|
| + base::AutoLock lock(metrics_service_lock_);
|
|
|
| - GetInstance()->SetReporting(false);
|
| - GetInstance()->SetRecording(false);
|
| - }
|
| -
|
| - if (GetInstance()->user_permits_upload_)
|
| - g_metrics_upload_thread_.Get().Stop();
|
| + GetInstance()->SetReporting(false);
|
| + GetInstance()->SetRecording(false);
|
| }
|
|
|
| void MetricsService::SetRecording(bool enabled) {
|
| + DCHECK_EQ(thread_, base::PlatformThread::CurrentId());
|
| if (enabled == recording_active_)
|
| return;
|
|
|
|
|