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

Side by Side 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: code review fixes part 2 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/metrics/antivirus_metrics_provider_win.h"
6
7 #include <iwscapi.h>
8 #include <stddef.h>
9 #include <windows.h>
10 #include <wscapi.h>
11
12 #include <string>
13
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/feature_list.h"
17 #include "base/file_version_info_win.h"
18 #include "base/files/file_path.h"
19 #include "base/files/file_util.h"
20 #include "base/metrics/field_trial.h"
21 #include "base/metrics/histogram.h"
22 #include "base/path_service.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/sys_string_conversions.h"
25 #include "base/task_runner_util.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "base/version.h"
28 #include "base/win/scoped_bstr.h"
29 #include "base/win/scoped_com_initializer.h"
30 #include "base/win/scoped_comptr.h"
31 #include "base/win/windows_version.h"
32 #include "chrome/common/channel_info.h"
33 #include "components/metrics/proto/system_profile.pb.h"
34 #include "components/variations/metrics_util.h"
35 #include "components/version_info/version_info.h"
36
37 namespace {
38
39 bool ShouldReportFullNames() {
40 // The expectation is that this will be disabled for the majority of users,
41 // but this allows a small group to be enabled on other channels if there are
42 // a large percentage of hashes collected on these channels that are not
43 // resolved to names previously collected on Canary channel.
44 bool enabled =
45 base::FeatureList::IsEnabled(AntiVirusMetricsProvider::kFeature);
46
47 if (chrome::GetChannel() == version_info::Channel::CANARY)
48 return true;
49
50 return enabled;
51 }
52
53 // Helper function for expanding all environment variables in |path|.
54 std::wstring ExpandEnvironmentVariables(const std::wstring& path) {
55 static const DWORD kMaxBuffer = 32 * 1024; // Max according to MSDN.
56 std::wstring path_expanded;
57 DWORD path_len = MAX_PATH;
58 do {
59 DWORD result = ExpandEnvironmentStrings(
60 path.c_str(), base::WriteInto(&path_expanded, path_len), path_len);
61 if (!result) {
62 // Failed to expand variables. Return the original string.
63 DPLOG(ERROR) << path;
64 break;
65 }
66 if (result <= path_len)
67 return path_expanded.substr(0, result - 1);
68 path_len = result;
69 } while (path_len < kMaxBuffer);
70
71 return path;
72 }
73
74 // Helper function to take a |path| to a file, that might contain environment
75 // strings, and read the file version information in |product_version|. Returns
76 // true if it was possible to extract the file information correctly.
77 bool GetProductVersion(std::wstring* path, std::string* product_version) {
78 base::FilePath full_path(ExpandEnvironmentVariables(*path));
79
80 #if !defined(_WIN64)
81 if (!base::PathExists(full_path)) {
82 // On 32-bit builds, path might contain C:\Program Files (x86) instead of
83 // C:\Program Files.
84 base::ReplaceFirstSubstringAfterOffset(path, 0, L"%ProgramFiles%",
85 L"%ProgramW6432%");
86 full_path = base::FilePath(ExpandEnvironmentVariables(*path));
87 }
88 #endif // !defined(_WIN64)
89 std::unique_ptr<FileVersionInfo> version_info(
90 FileVersionInfo::CreateFileVersionInfo(full_path));
91
92 // It is not an error if the product version cannot be read, so continue in
93 // this case.
94 if (version_info.get()) {
95 FileVersionInfoWin* version_info_win =
96 static_cast<FileVersionInfoWin*>(version_info.get());
97 *product_version =
98 std::move(base::SysWideToUTF8(version_info_win->product_version()));
99 return true;
100 }
101
102 return false;
103 }
104
105 } // namespace
106
107 AntiVirusMetricsProvider::AntiVirusMetricsProvider(
108 scoped_refptr<base::SequencedTaskRunner> file_thread)
109 : file_thread_(file_thread), weak_ptr_factory_(this) {}
110
111 AntiVirusMetricsProvider::~AntiVirusMetricsProvider() {}
112
113 void AntiVirusMetricsProvider::ProvideSystemProfileMetrics(
114 metrics::SystemProfileProto* system_profile_proto) {
115 for (const auto& av_product : av_products_) {
116 auto product = system_profile_proto->add_antivirus_product();
117 *product = std::move(av_product);
Alexei Svitkine (slow) 2016/06/03 15:48:33 This doesn't look right to me. This function will
Will Harris 2016/06/03 20:51:30 so it turns out because I am using a const iterato
118 }
119 }
120
121 void AntiVirusMetricsProvider::GetAntiVirusMetrics(
122 const base::Closure& done_callback) {
123 base::PostTaskAndReplyWithResult(
124 file_thread_.get(), FROM_HERE,
125 base::Bind(&AntiVirusMetricsProvider::GetAntiVirusProductsOnFileThread),
126 base::Bind(&AntiVirusMetricsProvider::GotAntiVirusProducts,
127 weak_ptr_factory_.GetWeakPtr(), done_callback));
128 }
129
130 // static
131 AntiVirusMetricsProvider::AvProductList
132 AntiVirusMetricsProvider::GetAntiVirusProductsOnFileThread() {
133 AvProductList av_products;
134
135 ResultCode result = FillAntiVirusProducts(&av_products);
136
137 UMA_HISTOGRAM_ENUMERATION("AntiVirusMetricsProvider.Result",
Alexei Svitkine (slow) 2016/06/03 15:48:33 Nit: Prefix the name with "UMA."
Will Harris 2016/06/03 20:51:30 Done.
138 result,
139 RESULT_COUNT);
140
141 return av_products;
142 }
143
144 void AntiVirusMetricsProvider::GotAntiVirusProducts(
145 const base::Closure& done_callback,
146 const AvProductList& av_products) {
147 DCHECK(thread_checker_.CalledOnValidThread());
148 av_products_ = av_products;
149 done_callback.Run();
150 }
151
152 // static
153 AntiVirusMetricsProvider::ResultCode
154 AntiVirusMetricsProvider::FillAntiVirusProducts(AvProductList* products) {
155 AvProductList result_list;
156 base::ThreadRestrictions::AssertIOAllowed();
157 base::win::ScopedCOMInitializer com_initializer;
158
159 if (!com_initializer.succeeded())
160 return RESULT_FAILED_TO_INITIALIZE_COM;
161
162 base::win::ScopedComPtr<IWSCProductList> product_list;
163 HRESULT result =
164 CoCreateInstance(__uuidof(WSCProductList), NULL, CLSCTX_INPROC_SERVER,
165 __uuidof(IWSCProductList), product_list.ReceiveVoid());
166 if (FAILED(result))
167 return RESULT_FAILED_TO_CREATE_INSTANCE;
168
169 result = product_list->Initialize(WSC_SECURITY_PROVIDER_ANTIVIRUS);
170 if (FAILED(result))
171 return RESULT_FAILED_TO_INITIALIZE_PRODUCT_LIST;
172
173 LONG product_count;
174 result = product_list->get_Count(&product_count);
175 if (FAILED(result))
176 return RESULT_FAILED_TO_GET_PRODUCT_COUNT;
177
178 for (LONG i = 0; i < product_count; i++) {
179 IWscProduct* product = nullptr;
180 result = product_list->get_Item(i, &product);
181 if (FAILED(result))
182 return RESULT_FAILED_TO_GET_ITEM;
183
184 static_assert(metrics::SystemProfileProto::AntiVirusState::
185 SystemProfileProto_AntiVirusState_STATE_ON ==
186 static_cast<metrics::SystemProfileProto::AntiVirusState>(
187 WSC_SECURITY_PRODUCT_STATE_ON),
188 "proto and API values must be the same");
189 static_assert(metrics::SystemProfileProto::AntiVirusState::
190 SystemProfileProto_AntiVirusState_STATE_OFF ==
191 static_cast<metrics::SystemProfileProto::AntiVirusState>(
192 WSC_SECURITY_PRODUCT_STATE_OFF),
193 "proto and API values must be the same");
194 static_assert(metrics::SystemProfileProto::AntiVirusState::
195 SystemProfileProto_AntiVirusState_STATE_SNOOZED ==
196 static_cast<metrics::SystemProfileProto::AntiVirusState>(
197 WSC_SECURITY_PRODUCT_STATE_SNOOZED),
198 "proto and API values must be the same");
199 static_assert(metrics::SystemProfileProto::AntiVirusState::
200 SystemProfileProto_AntiVirusState_STATE_EXPIRED ==
201 static_cast<metrics::SystemProfileProto::AntiVirusState>(
202 WSC_SECURITY_PRODUCT_STATE_EXPIRED),
203 "proto and API values must be the same");
204
205 AvProduct av_product;
206 WSC_SECURITY_PRODUCT_STATE product_state;
207 result = product->get_ProductState(&product_state);
208 if (FAILED(result))
209 return RESULT_FAILED_TO_GET_PRODUCT_STATE;
210
211 if (!metrics::SystemProfileProto_AntiVirusState_IsValid(product_state))
212 return RESULT_PRODUCT_STATE_INVALID;
213
214 av_product.set_product_state(
215 static_cast<metrics::SystemProfileProto::AntiVirusState>(
216 product_state));
217
218 base::win::ScopedBstr product_name;
219 result = product->get_ProductName(product_name.Receive());
220 if (FAILED(result))
221 return RESULT_FAILED_TO_GET_PRODUCT_NAME;
222 std::string name =
223 base::SysWideToUTF8(std::wstring(product_name, product_name.Length()));
224 product_name.Release();
225 if (ShouldReportFullNames())
226 av_product.set_product_name(name);
227 av_product.set_product_name_hash(metrics::HashName(name));
228
229 base::win::ScopedBstr remediation_path;
230 result = product->get_RemediationPath(remediation_path.Receive());
231 if (FAILED(result))
232 return RESULT_FAILED_TO_GET_REMEDIATION_PATH;
233 std::wstring path_str(remediation_path, remediation_path.Length());
234 remediation_path.Release();
235
236 std::string product_version;
237 // Not a failure if the product version cannot be read from the file on
238 // disk.
239 if (GetProductVersion(&path_str, &product_version)) {
240 if (ShouldReportFullNames())
241 av_product.set_product_version(product_version);
242 av_product.set_product_version_hash(metrics::HashName(product_version));
243 }
244
245 result_list.push_back(av_product);
246 }
247
248 *products = std::move(result_list);
249
250 return RESULT_SUCCESS;
251 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698