Chromium Code Reviews| 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 |
| index cc098a473921cb5fe3d2f00b14a09c173ff82ad2..025d907e3f15b4334ee66f4be026eb57ca8f99f8 100644 |
| --- a/chrome/browser/metrics/antivirus_metrics_provider_win.cc |
| +++ b/chrome/browser/metrics/antivirus_metrics_provider_win.cc |
| @@ -6,6 +6,7 @@ |
| #include <iwscapi.h> |
| #include <stddef.h> |
| +#include <wbemidl.h> |
| #include <windows.h> |
| #include <wscapi.h> |
| @@ -28,6 +29,7 @@ |
| #include "base/win/scoped_bstr.h" |
| #include "base/win/scoped_com_initializer.h" |
| #include "base/win/scoped_comptr.h" |
| +#include "base/win/scoped_variant.h" |
| #include "base/win/windows_version.h" |
| #include "chrome/common/channel_info.h" |
| #include "components/metrics/proto/system_profile.pb.h" |
| @@ -36,6 +38,20 @@ |
| namespace { |
| +#pragma pack(push) |
| +#pragma pack(1) |
| +struct PRODUCT_STATE { |
|
Will Harris
2016/06/16 19:05:33
Source: http://neophob.com/2010/03/wmi-query-windo
|
| + uint8_t unknown_1 : 4; |
| + uint8_t definition_state : 4; // 1 = out of date, 0 = up to date. |
| + uint8_t unknown_2 : 4; |
| + uint8_t security_state : 4; // 0 = inactive, 1 = active, 2 = snoozed. |
| + uint8_t security_provider; // matches WSC_SECURITY_PROVIDER enum. |
| + uint8_t unknown_3; |
| +}; |
| +#pragma pack(pop) |
| + |
| +static_assert(sizeof(PRODUCT_STATE) == 4, "wrong packing!"); |
| + |
| 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 |
| @@ -137,7 +153,12 @@ std::vector<AntiVirusMetricsProvider::AvProduct> |
| AntiVirusMetricsProvider::GetAntiVirusProductsOnFileThread() { |
| std::vector<AvProduct> av_products; |
| - ResultCode result = FillAntiVirusProducts(&av_products); |
| + ResultCode result = RESULT_GENERIC_FAILURE; |
| + |
| + if (base::win::GetVersion() >= base::win::VERSION_WIN8) |
| + result = FillAntiVirusProductsFromWSC(&av_products); |
| + else |
| + result = FillAntiVirusProductsFromWMI(&av_products); |
|
Will Harris
2016/06/16 19:05:33
Note: The WMI interface is not officially document
|
| UMA_HISTOGRAM_ENUMERATION("UMA.AntiVirusMetricsProvider.Result", |
| result, |
| @@ -156,7 +177,7 @@ void AntiVirusMetricsProvider::GotAntiVirusProducts( |
| // static |
| AntiVirusMetricsProvider::ResultCode |
| -AntiVirusMetricsProvider::FillAntiVirusProducts( |
| +AntiVirusMetricsProvider::FillAntiVirusProductsFromWSC( |
| std::vector<AvProduct>* products) { |
| std::vector<AvProduct> result_list; |
| base::ThreadRestrictions::AssertIOAllowed(); |
| @@ -251,7 +272,134 @@ AntiVirusMetricsProvider::FillAntiVirusProducts( |
| result_list.push_back(av_product); |
| } |
| - *products = std::move(result_list); |
| + products->insert(products->end(), result_list.begin(), result_list.end()); |
| + |
| + return RESULT_SUCCESS; |
| +} |
| + |
| +AntiVirusMetricsProvider::ResultCode |
| +AntiVirusMetricsProvider::FillAntiVirusProductsFromWMI( |
| + 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<IWbemLocator> wmi_locator; |
| + HRESULT hr = |
| + wmi_locator.CreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER); |
| + if (FAILED(hr)) |
| + return RESULT_FAILED_TO_CREATE_INSTANCE; |
| + |
| + base::win::ScopedComPtr<IWbemServices> wmi_services; |
| + hr = wmi_locator->ConnectServer( |
| + base::win::ScopedBstr(L"ROOT\\SecurityCenter2"), NULL, NULL, 0, NULL, 0, |
| + 0, wmi_services.Receive()); |
| + if (FAILED(hr)) |
| + return RESULT_FAILED_TO_CONNECT_TO_WMI; |
| + |
| + hr = ::CoSetProxyBlanket(wmi_services.get(), RPC_C_AUTHN_WINNT, |
| + RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, |
| + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); |
| + if (FAILED(hr)) |
| + return RESULT_FAILED_TO_SET_SECURITY_BLANKET; |
| + |
| + base::win::ScopedBstr query_language(L"WQL"); |
| + base::win::ScopedBstr query(L"SELECT * FROM AntiVirusProduct"); |
| + base::win::ScopedComPtr<IEnumWbemClassObject> enumerator; |
| + |
| + hr = wmi_services->ExecQuery( |
| + query_language, query, |
| + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, |
| + enumerator.Receive()); |
| + if (FAILED(hr)) |
| + return RESULT_FAILED_TO_EXEC_WMI_QUERY; |
| + |
| + while (true) { |
| + base::win::ScopedComPtr<IWbemClassObject> class_object; |
| + ULONG items_returned = 0; |
| + hr = enumerator->Next(WBEM_INFINITE, 1, class_object.Receive(), |
| + &items_returned); |
| + if (FAILED(hr)) |
| + return RESULT_FAILED_TO_ITERATE_RESULTS; |
| + |
| + if (hr == WBEM_S_FALSE || items_returned == 0) |
| + break; |
| + |
| + AvProduct av_product; |
| + av_product.set_product_state( |
| + metrics::SystemProfileProto::AntiVirusState:: |
| + SystemProfileProto_AntiVirusState_STATE_ON); |
| + |
| + base::win::ScopedVariant product_state; |
| + hr = class_object->Get(L"productState", 0, product_state.Receive(), 0, 0); |
| + |
| + if (FAILED(hr) || product_state.type() != VT_I4) |
| + return RESULT_FAILED_TO_GET_PRODUCT_STATE; |
| + |
| + LONG state_val = V_I4(product_state.ptr()); |
| + switch (reinterpret_cast<PRODUCT_STATE*>(&state_val)->security_state) { |
| + case 0: |
| + av_product.set_product_state( |
| + metrics::SystemProfileProto::AntiVirusState:: |
| + SystemProfileProto_AntiVirusState_STATE_OFF); |
| + break; |
| + case 1: |
| + av_product.set_product_state( |
| + metrics::SystemProfileProto::AntiVirusState:: |
| + SystemProfileProto_AntiVirusState_STATE_ON); |
| + break; |
| + case 2: |
| + av_product.set_product_state( |
| + metrics::SystemProfileProto::AntiVirusState:: |
| + SystemProfileProto_AntiVirusState_STATE_SNOOZED); |
| + break; |
| + default: |
| + // unknown state. |
| + return RESULT_PRODUCT_STATE_INVALID; |
| + break; |
| + } |
| + |
| + base::win::ScopedVariant display_name; |
| + hr = class_object->Get(L"displayName", 0, display_name.Receive(), 0, 0); |
| + |
| + if (FAILED(hr) || display_name.type() != VT_BSTR) |
| + return RESULT_FAILED_TO_GET_PRODUCT_NAME; |
| + |
| + // Owned by ScopedVariant. |
| + BSTR temp_bstr = V_BSTR(display_name.ptr()); |
| + std::string name(base::SysWideToUTF8( |
| + std::wstring(temp_bstr, ::SysStringLen(temp_bstr)))); |
| + |
| + if (ShouldReportFullNames()) |
| + av_product.set_product_name(name); |
| + av_product.set_product_name_hash(metrics::HashName(name)); |
| + |
| + base::win::ScopedVariant exe_path; |
| + hr = class_object->Get(L"pathToSignedProductExe", 0, exe_path.Receive(), 0, |
| + 0); |
| + |
| + if (FAILED(hr) || exe_path.type() != VT_BSTR) |
| + return RESULT_FAILED_TO_GET_REMEDIATION_PATH; |
| + |
| + temp_bstr = V_BSTR(exe_path.ptr()); |
| + std::wstring path_str(temp_bstr, ::SysStringLen(temp_bstr)); |
| + |
| + 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->insert(products->end(), result_list.begin(), result_list.end()); |
| return RESULT_SUCCESS; |
| } |