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

Unified Diff: chrome/browser/metrics/antivirus_metrics_provider_win.cc

Issue 2009773007: Add AntiVirus information to the system profile. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 6 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/metrics/antivirus_metrics_provider_win.cc
diff --git a/chrome/browser/metrics/antivirus_metrics_provider_win.cc b/chrome/browser/metrics/antivirus_metrics_provider_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..cc098a473921cb5fe3d2f00b14a09c173ff82ad2
--- /dev/null
+++ b/chrome/browser/metrics/antivirus_metrics_provider_win.cc
@@ -0,0 +1,257 @@
+// Copyright 2016 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.
+
+#include "chrome/browser/metrics/antivirus_metrics_provider_win.h"
+
+#include <iwscapi.h>
+#include <stddef.h>
+#include <windows.h>
+#include <wscapi.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/feature_list.h"
+#include "base/file_version_info_win.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/version.h"
+#include "base/win/scoped_bstr.h"
+#include "base/win/scoped_com_initializer.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/windows_version.h"
+#include "chrome/common/channel_info.h"
+#include "components/metrics/proto/system_profile.pb.h"
+#include "components/variations/metrics_util.h"
+#include "components/version_info/version_info.h"
+
+namespace {
+
+bool ShouldReportFullNames() {
+ // The expectation is that this will be disabled for the majority of users,
+ // but this allows a small group to be enabled on other channels if there are
+ // a large percentage of hashes collected on these channels that are not
+ // resolved to names previously collected on Canary channel.
+ bool enabled = base::FeatureList::IsEnabled(
+ AntiVirusMetricsProvider::kReportNamesFeature);
+
+ if (chrome::GetChannel() == version_info::Channel::CANARY)
+ return true;
+
+ return enabled;
+}
+
+// Helper function for expanding all environment variables in |path|.
+std::wstring ExpandEnvironmentVariables(const std::wstring& path) {
+ static const DWORD kMaxBuffer = 32 * 1024; // Max according to MSDN.
+ std::wstring path_expanded;
+ DWORD path_len = MAX_PATH;
+ do {
+ DWORD result = ExpandEnvironmentStrings(
+ path.c_str(), base::WriteInto(&path_expanded, path_len), path_len);
+ if (!result) {
+ // Failed to expand variables. Return the original string.
+ DPLOG(ERROR) << path;
+ break;
+ }
+ if (result <= path_len)
+ return path_expanded.substr(0, result - 1);
+ path_len = result;
+ } while (path_len < kMaxBuffer);
+
+ return path;
+}
+
+// Helper function to take a |path| to a file, that might contain environment
+// strings, and read the file version information in |product_version|. Returns
+// true if it was possible to extract the file information correctly.
+bool GetProductVersion(std::wstring* path, std::string* product_version) {
+ base::FilePath full_path(ExpandEnvironmentVariables(*path));
+
+#if !defined(_WIN64)
+ if (!base::PathExists(full_path)) {
+ // On 32-bit builds, path might contain C:\Program Files (x86) instead of
+ // C:\Program Files.
+ base::ReplaceFirstSubstringAfterOffset(path, 0, L"%ProgramFiles%",
+ L"%ProgramW6432%");
+ full_path = base::FilePath(ExpandEnvironmentVariables(*path));
+ }
+#endif // !defined(_WIN64)
+ std::unique_ptr<FileVersionInfo> version_info(
+ FileVersionInfo::CreateFileVersionInfo(full_path));
+
+ // It is not an error if the product version cannot be read, so continue in
+ // this case.
+ if (version_info.get()) {
+ FileVersionInfoWin* version_info_win =
+ static_cast<FileVersionInfoWin*>(version_info.get());
+ std::string version_str =
+ base::SysWideToUTF8(version_info_win->product_version());
+
+ *product_version = std::move(version_str);
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+constexpr base::Feature AntiVirusMetricsProvider::kReportNamesFeature;
+
+AntiVirusMetricsProvider::AntiVirusMetricsProvider(
+ scoped_refptr<base::TaskRunner> task_runner)
+ : task_runner_(task_runner), weak_ptr_factory_(this) {}
+
+AntiVirusMetricsProvider::~AntiVirusMetricsProvider() {}
+
+void AntiVirusMetricsProvider::ProvideSystemProfileMetrics(
+ metrics::SystemProfileProto* system_profile_proto) {
+ for (const auto& av_product : av_products_) {
+ metrics::SystemProfileProto_AntiVirusProduct* product =
+ system_profile_proto->add_antivirus_product();
+ *product = av_product;
+ }
+}
+
+void AntiVirusMetricsProvider::GetAntiVirusMetrics(
+ const base::Closure& done_callback) {
+ base::PostTaskAndReplyWithResult(
+ task_runner_.get(), FROM_HERE,
+ base::Bind(&AntiVirusMetricsProvider::GetAntiVirusProductsOnFileThread),
+ base::Bind(&AntiVirusMetricsProvider::GotAntiVirusProducts,
+ weak_ptr_factory_.GetWeakPtr(), done_callback));
+}
+
+// static
+std::vector<AntiVirusMetricsProvider::AvProduct>
+AntiVirusMetricsProvider::GetAntiVirusProductsOnFileThread() {
+ std::vector<AvProduct> av_products;
+
+ ResultCode result = FillAntiVirusProducts(&av_products);
+
+ UMA_HISTOGRAM_ENUMERATION("UMA.AntiVirusMetricsProvider.Result",
+ result,
+ RESULT_COUNT);
+
+ return av_products;
+}
+
+void AntiVirusMetricsProvider::GotAntiVirusProducts(
+ const base::Closure& done_callback,
+ const std::vector<AvProduct>& av_products) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ av_products_ = av_products;
+ done_callback.Run();
+}
+
+// static
+AntiVirusMetricsProvider::ResultCode
+AntiVirusMetricsProvider::FillAntiVirusProducts(
+ std::vector<AvProduct>* products) {
+ std::vector<AvProduct> result_list;
+ base::ThreadRestrictions::AssertIOAllowed();
+ base::win::ScopedCOMInitializer com_initializer;
+
+ if (!com_initializer.succeeded())
+ return RESULT_FAILED_TO_INITIALIZE_COM;
+
+ base::win::ScopedComPtr<IWSCProductList> product_list;
+ HRESULT result =
+ CoCreateInstance(__uuidof(WSCProductList), NULL, CLSCTX_INPROC_SERVER,
+ __uuidof(IWSCProductList), product_list.ReceiveVoid());
+ if (FAILED(result))
+ return RESULT_FAILED_TO_CREATE_INSTANCE;
+
+ result = product_list->Initialize(WSC_SECURITY_PROVIDER_ANTIVIRUS);
+ if (FAILED(result))
+ return RESULT_FAILED_TO_INITIALIZE_PRODUCT_LIST;
+
+ LONG product_count;
+ result = product_list->get_Count(&product_count);
+ if (FAILED(result))
+ return RESULT_FAILED_TO_GET_PRODUCT_COUNT;
+
+ for (LONG i = 0; i < product_count; i++) {
+ IWscProduct* product = nullptr;
+ result = product_list->get_Item(i, &product);
+ if (FAILED(result))
+ return RESULT_FAILED_TO_GET_ITEM;
+
+ static_assert(metrics::SystemProfileProto::AntiVirusState::
+ SystemProfileProto_AntiVirusState_STATE_ON ==
+ static_cast<metrics::SystemProfileProto::AntiVirusState>(
+ WSC_SECURITY_PRODUCT_STATE_ON),
+ "proto and API values must be the same");
+ static_assert(metrics::SystemProfileProto::AntiVirusState::
+ SystemProfileProto_AntiVirusState_STATE_OFF ==
+ static_cast<metrics::SystemProfileProto::AntiVirusState>(
+ WSC_SECURITY_PRODUCT_STATE_OFF),
+ "proto and API values must be the same");
+ static_assert(metrics::SystemProfileProto::AntiVirusState::
+ SystemProfileProto_AntiVirusState_STATE_SNOOZED ==
+ static_cast<metrics::SystemProfileProto::AntiVirusState>(
+ WSC_SECURITY_PRODUCT_STATE_SNOOZED),
+ "proto and API values must be the same");
+ static_assert(metrics::SystemProfileProto::AntiVirusState::
+ SystemProfileProto_AntiVirusState_STATE_EXPIRED ==
+ static_cast<metrics::SystemProfileProto::AntiVirusState>(
+ WSC_SECURITY_PRODUCT_STATE_EXPIRED),
+ "proto and API values must be the same");
+
+ AvProduct av_product;
+ WSC_SECURITY_PRODUCT_STATE product_state;
+ result = product->get_ProductState(&product_state);
+ if (FAILED(result))
+ return RESULT_FAILED_TO_GET_PRODUCT_STATE;
+
+ if (!metrics::SystemProfileProto_AntiVirusState_IsValid(product_state))
+ return RESULT_PRODUCT_STATE_INVALID;
+
+ av_product.set_product_state(
+ static_cast<metrics::SystemProfileProto::AntiVirusState>(
+ product_state));
+
+ base::win::ScopedBstr product_name;
+ result = product->get_ProductName(product_name.Receive());
+ if (FAILED(result))
+ return RESULT_FAILED_TO_GET_PRODUCT_NAME;
+ std::string name =
+ base::SysWideToUTF8(std::wstring(product_name, product_name.Length()));
+ product_name.Release();
+ if (ShouldReportFullNames())
+ av_product.set_product_name(name);
+ av_product.set_product_name_hash(metrics::HashName(name));
+
+ base::win::ScopedBstr remediation_path;
+ result = product->get_RemediationPath(remediation_path.Receive());
+ if (FAILED(result))
+ return RESULT_FAILED_TO_GET_REMEDIATION_PATH;
+ std::wstring path_str(remediation_path, remediation_path.Length());
+ remediation_path.Release();
+
+ std::string product_version;
+ // Not a failure if the product version cannot be read from the file on
+ // disk.
+ if (GetProductVersion(&path_str, &product_version)) {
+ if (ShouldReportFullNames())
+ av_product.set_product_version(product_version);
+ av_product.set_product_version_hash(metrics::HashName(product_version));
+ }
+
+ result_list.push_back(av_product);
+ }
+
+ *products = std::move(result_list);
+
+ return RESULT_SUCCESS;
+}

Powered by Google App Engine
This is Rietveld 408576698