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

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: hash the product name and version 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/file_version_info_win.h"
17 #include "base/files/file_path.h"
18 #include "base/files/file_util.h"
19 #include "base/metrics/field_trial.h"
20 #include "base/path_service.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/sys_string_conversions.h"
23 #include "base/task_runner_util.h"
24 #include "base/threading/thread_restrictions.h"
25 #include "base/version.h"
26 #include "base/win/scoped_bstr.h"
27 #include "base/win/scoped_com_initializer.h"
28 #include "base/win/scoped_comptr.h"
29 #include "base/win/windows_version.h"
30 #include "chrome/common/channel_info.h"
31 #include "components/metrics/proto/system_profile.pb.h"
32 #include "components/variations/metrics_util.h"
33 #include "components/version_info/version_info.h"
34
35 namespace metrics {
Alexei Svitkine (slow) 2016/06/01 20:42:34 Only things in components/metrics should be in the
Will Harris 2016/06/02 20:36:26 Happy to move out of namespace but there seems to
Alexei Svitkine (slow) 2016/06/02 21:46:57 Sigh. I didn't realize this many things were incon
Will Harris 2016/06/02 23:57:17 I'll leave this new code outside metrics namespace
36
37 namespace {
38
39 bool ShouldReportFullNames() {
40 const std::string group_name =
41 base::FieldTrialList::FindFullName("ReportFullAVProductDetails");
42
43 if (chrome::GetChannel() == version_info::Channel::CANARY ||
44 chrome::GetChannel() == version_info::Channel::UNKNOWN) {
Alexei Svitkine (slow) 2016/06/01 20:42:35 I'd rather we don't default unknown to true. Canar
Will Harris 2016/06/01 23:57:08 I think the tests/bots run as unknown. if I make i
Alexei Svitkine (slow) 2016/06/02 15:17:18 Then I suggest your tests to explicitly enable the
Will Harris 2016/06/02 20:36:27 Done.
45 return true;
46 }
47
48 return base::StartsWith(group_name, "Enabled",
49 base::CompareCase::INSENSITIVE_ASCII);
Alexei Svitkine (slow) 2016/06/01 20:42:35 Use base::Feature API instead - which is now the b
Will Harris 2016/06/02 20:36:27 Done.
50 }
51
52 // Helper function for expanding all environment variables in |path|.
53 std::wstring ExpandEnvironmentVariables(const std::wstring& path) {
54 static const DWORD kMaxBuffer = 32 * 1024; // Max according to MSDN.
55 std::wstring path_expanded;
56 DWORD path_len = MAX_PATH;
57 do {
58 DWORD result = ExpandEnvironmentStrings(
59 path.c_str(), base::WriteInto(&path_expanded, path_len), path_len);
60 if (!result) {
61 // Failed to expand variables. Return the original string.
62 DPLOG(ERROR) << path;
63 break;
64 }
65 if (result <= path_len)
66 return path_expanded.substr(0, result - 1);
67 path_len = result;
68 } while (path_len < kMaxBuffer);
69
70 return path;
71 }
72
73 } // namespace
74
75 AntiVirusMetricsProvider::AntiVirusMetricsProvider(
76 scoped_refptr<base::SequencedTaskRunner> file_thread)
77 : file_thread_(file_thread), weak_ptr_factory_(this) {}
78
79 AntiVirusMetricsProvider::~AntiVirusMetricsProvider() {}
80
81 void AntiVirusMetricsProvider::ProvideSystemProfileMetrics(
82 SystemProfileProto* system_profile_proto) {
83 for (const auto& av_product : av_products_) {
84 auto product = system_profile_proto->add_antivirus_product();
85
86 std::string product_name = base::SysWideToUTF8(av_product.product_name);
87
88 if (ShouldReportFullNames())
89 product->set_product_name(product_name);
90 product->set_product_name_hash(HashName(product_name));
Alexei Svitkine (slow) 2016/06/01 20:42:35 How about doing all this logic once (as opposed to
Will Harris 2016/06/02 20:36:27 I wanted to have the FillAntiVirusProducts be call
Alexei Svitkine (slow) 2016/06/02 21:46:57 I think it's inefficient to do this logic over and
91
92 if (!av_product.product_version.empty()) {
93 std::string product_version =
94 base::SysWideToUTF8(av_product.product_version);
95 if (ShouldReportFullNames())
96 product->set_product_version(product_version);
97 product->set_product_version_hash(HashName(product_version));
98 }
99
100 product->set_product_state(av_product.product_state);
101 }
102 }
103
104 void AntiVirusMetricsProvider::GetAntiVirusMetrics(
105 const base::Closure& done_callback) {
106 base::PostTaskAndReplyWithResult(
107 file_thread_.get(), FROM_HERE,
108 base::Bind(&AntiVirusMetricsProvider::GetAntiVirusProductsOnFileThread),
109 base::Bind(&AntiVirusMetricsProvider::GotAntiVirusProducts,
110 weak_ptr_factory_.GetWeakPtr(), done_callback));
111 }
112
113 // static
114 AntiVirusMetricsProvider::AvProductList
115 AntiVirusMetricsProvider::GetAntiVirusProductsOnFileThread() {
116 AvProductList av_products;
117
118 FillAntiVirusProducts(&av_products);
119
120 return av_products;
121 }
122
123 void AntiVirusMetricsProvider::GotAntiVirusProducts(
124 const base::Closure& done_callback,
125 const AvProductList& av_products) {
126 DCHECK(thread_checker_.CalledOnValidThread());
127 av_products_ = av_products;
128 done_callback.Run();
129 }
130
131 // static
132 bool AntiVirusMetricsProvider::FillAntiVirusProducts(AvProductList* products) {
133 base::ThreadRestrictions::AssertIOAllowed();
134 base::win::ScopedCOMInitializer com_initializer;
135
136 if (!com_initializer.succeeded())
137 return false;
138
139 base::win::ScopedComPtr<IWSCProductList> product_list;
140 HRESULT result =
141 CoCreateInstance(__uuidof(WSCProductList), NULL, CLSCTX_INPROC_SERVER,
142 __uuidof(IWSCProductList), product_list.ReceiveVoid());
143 if (FAILED(result))
144 return false;
145
146 result = product_list->Initialize(WSC_SECURITY_PROVIDER_ANTIVIRUS);
147 if (FAILED(result))
148 return false;
149
150 LONG product_count;
151 result = product_list->get_Count(&product_count);
152 if (FAILED(result))
153 return false;
154
155 for (LONG i = 0; i < product_count; i++) {
156 IWscProduct* product = nullptr;
157 result = product_list->get_Item(i, &product);
158 if (FAILED(result))
159 return false;
160
161 static_assert(SystemProfileProto::AntiVirusState::
162 SystemProfileProto_AntiVirusState_STATE_ON ==
163 static_cast<SystemProfileProto::AntiVirusState>(
164 WSC_SECURITY_PRODUCT_STATE_ON),
165 "proto and API values must be the same");
166 static_assert(SystemProfileProto::AntiVirusState::
167 SystemProfileProto_AntiVirusState_STATE_OFF ==
168 static_cast<SystemProfileProto::AntiVirusState>(
169 WSC_SECURITY_PRODUCT_STATE_OFF),
170 "proto and API values must be the same");
171 static_assert(SystemProfileProto::AntiVirusState::
172 SystemProfileProto_AntiVirusState_STATE_SNOOZED ==
173 static_cast<SystemProfileProto::AntiVirusState>(
174 WSC_SECURITY_PRODUCT_STATE_SNOOZED),
175 "proto and API values must be the same");
176 static_assert(SystemProfileProto::AntiVirusState::
177 SystemProfileProto_AntiVirusState_STATE_EXPIRED ==
178 static_cast<SystemProfileProto::AntiVirusState>(
179 WSC_SECURITY_PRODUCT_STATE_EXPIRED),
180 "proto and API values must be the same");
181
182 AvProduct av_product;
183 WSC_SECURITY_PRODUCT_STATE product_state;
184 result = product->get_ProductState(&product_state);
185 if (FAILED(result))
186 return false;
187
188 av_product.product_state =
189 static_cast<SystemProfileProto::AntiVirusState>(product_state);
190
191 if (av_product.product_state < SystemProfileProto::AntiVirusState_MIN ||
192 av_product.product_state > SystemProfileProto::AntiVirusState_MAX) {
193 return false;
194 }
195
196 base::win::ScopedBstr product_name;
197 result = product->get_ProductName(product_name.Receive());
198 if (FAILED(result))
199 return false;
200 av_product.product_name = std::wstring(product_name, product_name.Length());
201 product_name.Release();
202
203 base::win::ScopedBstr remediation_path;
204 result = product->get_RemediationPath(remediation_path.Receive());
205 if (FAILED(result))
206 return false;
207 std::wstring path_str(remediation_path, remediation_path.Length());
208 remediation_path.Release();
209
210 base::FilePath full_path(ExpandEnvironmentVariables(path_str));
211
212 #if !defined(_WIN64)
213 if (!base::PathExists(full_path)) {
214 // On 32-bit builds, path might contain C:\Program Files (x86) instead of
215 // C:\Program Files.
216 base::ReplaceFirstSubstringAfterOffset(&path_str, 0, L"%ProgramFiles%",
217 L"%ProgramW6432%");
218 full_path = base::FilePath(ExpandEnvironmentVariables(path_str));
219 }
220 #endif // !defined(_WIN64)
221 std::unique_ptr<FileVersionInfo> version_info(
222 FileVersionInfo::CreateFileVersionInfo(full_path));
223
224 if (version_info.get()) {
225 FileVersionInfoWin* version_info_win =
226 static_cast<FileVersionInfoWin*>(version_info.get());
227 av_product.product_version = version_info_win->product_version();
228 } else {
229 av_product.product_version = std::wstring();
230 }
231
232 products->push_back(av_product);
233 }
234
235 return true;
236 }
237
238 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698