Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / chrome_elf_init_win.cc
blob3d568a69a46ae32568bec069f83140348b0c89e7
1 // Copyright 2014 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.
5 #include "base/bind.h"
6 #include "base/metrics/field_trial.h"
7 #include "base/metrics/histogram.h"
8 #include "base/metrics/sparse_histogram.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/win/registry.h"
11 #include "chrome/browser/chrome_elf_init_win.h"
12 #include "chrome_elf/blacklist/blacklist.h"
13 #include "chrome_elf/chrome_elf_constants.h"
14 #include "chrome_elf/dll_hash/dll_hash.h"
15 #include "components/variations/variations_associated_data.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "version.h" // NOLINT
19 const char kBrowserBlacklistTrialName[] = "BrowserBlacklist";
20 const char kBrowserBlacklistTrialDisabledGroupName[] = "NoBlacklist";
22 namespace {
24 // How long to wait, in seconds, before reporting for the second (and last
25 // time), what dlls were blocked from the browser process.
26 const int kBlacklistReportingDelaySec = 600;
28 // This enum is used to define the buckets for an enumerated UMA histogram.
29 // Hence,
30 // (a) existing enumerated constants should never be deleted or reordered, and
31 // (b) new constants should only be appended in front of
32 // BLACKLIST_SETUP_EVENT_MAX.
33 enum BlacklistSetupEventType {
34 // The blacklist beacon has placed to enable the browser blacklisting.
35 BLACKLIST_SETUP_ENABLED = 0,
37 // The blacklist was successfully enabled.
38 BLACKLIST_SETUP_RAN_SUCCESSFULLY,
40 // The blacklist setup code failed to execute.
41 BLACKLIST_SETUP_FAILED,
43 // The blacklist thunk setup code failed. This is probably an indication
44 // that something else patched that code first.
45 BLACKLIST_THUNK_SETUP_FAILED,
47 // Deprecated. The blacklist interception code failed to execute.
48 BLACKLIST_INTERCEPTION_FAILED,
50 // The blacklist was disabled for this run (after it failed too many times).
51 BLACKLIST_SETUP_DISABLED,
53 // Always keep this at the end.
54 BLACKLIST_SETUP_EVENT_MAX,
57 void RecordBlacklistSetupEvent(BlacklistSetupEventType blacklist_setup_event) {
58 UMA_HISTOGRAM_ENUMERATION("Blacklist.Setup",
59 blacklist_setup_event,
60 BLACKLIST_SETUP_EVENT_MAX);
63 // Report which DLLs were prevented from being loaded.
64 void ReportSuccessfulBlocks() {
65 // Figure out how many dlls were blocked.
66 int num_blocked_dlls = 0;
67 blacklist::SuccessfullyBlocked(NULL, &num_blocked_dlls);
69 if (num_blocked_dlls == 0)
70 return;
72 // Now retrieve the list of blocked dlls.
73 std::vector<const wchar_t*> blocked_dlls(num_blocked_dlls);
74 blacklist::SuccessfullyBlocked(&blocked_dlls[0], &num_blocked_dlls);
76 // Send up the hashes of the blocked dlls via UMA.
77 for (size_t i = 0; i < blocked_dlls.size(); ++i) {
78 std::string dll_name_utf8;
79 base::WideToUTF8(blocked_dlls[i], wcslen(blocked_dlls[i]), &dll_name_utf8);
80 int uma_hash = DllNameToHash(dll_name_utf8);
82 UMA_HISTOGRAM_SPARSE_SLOWLY("Blacklist.Blocked", uma_hash);
86 } // namespace
88 void InitializeChromeElf() {
89 if (base::FieldTrialList::FindFullName(kBrowserBlacklistTrialName) ==
90 kBrowserBlacklistTrialDisabledGroupName) {
91 // Disable the blacklist for all future runs by removing the beacon.
92 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER);
93 blacklist_registry_key.DeleteKey(blacklist::kRegistryBeaconPath);
94 } else {
95 AddFinchBlacklistToRegistry();
96 BrowserBlacklistBeaconSetup();
99 // Report all successful blacklist interceptions.
100 ReportSuccessfulBlocks();
102 // Schedule another task to report all sucessful interceptions later.
103 // This time delay should be long enough to catch any dlls that attempt to
104 // inject after Chrome has started up.
105 content::BrowserThread::PostDelayedTask(
106 content::BrowserThread::UI,
107 FROM_HERE,
108 base::Bind(&ReportSuccessfulBlocks),
109 base::TimeDelta::FromSeconds(kBlacklistReportingDelaySec));
112 // Note that running multiple chrome instances with distinct user data
113 // directories could lead to deletion (and/or replacement) of the finch
114 // blacklist registry data in one instance before the second has a chance to
115 // read those values.
116 void AddFinchBlacklistToRegistry() {
117 base::win::RegKey finch_blacklist_registry_key(
118 HKEY_CURRENT_USER, blacklist::kRegistryFinchListPath, KEY_SET_VALUE);
120 // No point in trying to continue if the registry key isn't valid.
121 if (!finch_blacklist_registry_key.Valid())
122 return;
124 // Delete and recreate the key to clear the registry.
125 finch_blacklist_registry_key.DeleteKey(L"");
126 finch_blacklist_registry_key.Create(
127 HKEY_CURRENT_USER, blacklist::kRegistryFinchListPath, KEY_SET_VALUE);
129 std::map<std::string, std::string> params;
130 variations::GetVariationParams(kBrowserBlacklistTrialName, &params);
132 for (std::map<std::string, std::string>::iterator it = params.begin();
133 it != params.end();
134 ++it) {
135 std::wstring name = base::UTF8ToWide(it->first);
136 std::wstring val = base::UTF8ToWide(it->second);
138 finch_blacklist_registry_key.WriteValue(name.c_str(), val.c_str());
142 void BrowserBlacklistBeaconSetup() {
143 base::win::RegKey blacklist_registry_key(HKEY_CURRENT_USER,
144 blacklist::kRegistryBeaconPath,
145 KEY_QUERY_VALUE | KEY_SET_VALUE);
147 // No point in trying to continue if the registry key isn't valid.
148 if (!blacklist_registry_key.Valid())
149 return;
151 // Record the results of the last blacklist setup.
152 DWORD blacklist_state = blacklist::BLACKLIST_STATE_MAX;
153 blacklist_registry_key.ReadValueDW(blacklist::kBeaconState, &blacklist_state);
155 if (blacklist_state == blacklist::BLACKLIST_ENABLED) {
156 // The blacklist setup didn't crash, so we report if it was enabled or not.
157 if (blacklist::IsBlacklistInitialized()) {
158 RecordBlacklistSetupEvent(BLACKLIST_SETUP_RAN_SUCCESSFULLY);
159 } else {
160 // The only way for the blacklist to be enabled, but not fully
161 // initialized is if the thunk setup failed. See blacklist.cc
162 // for more details.
163 RecordBlacklistSetupEvent(BLACKLIST_THUNK_SETUP_FAILED);
166 // Regardless of if the blacklist was fully enabled or not, report how many
167 // times we had to try to set it up.
168 DWORD attempt_count = 0;
169 blacklist_registry_key.ReadValueDW(blacklist::kBeaconAttemptCount,
170 &attempt_count);
171 UMA_HISTOGRAM_COUNTS_100("Blacklist.RetryAttempts.Success", attempt_count);
172 } else if (blacklist_state == blacklist::BLACKLIST_SETUP_FAILED) {
173 // We can set the state to disabled without checking that the maximum number
174 // of attempts was exceeded because blacklist.cc has already done this.
175 RecordBlacklistSetupEvent(BLACKLIST_SETUP_FAILED);
176 blacklist_registry_key.WriteValue(blacklist::kBeaconState,
177 blacklist::BLACKLIST_DISABLED);
178 } else if (blacklist_state == blacklist::BLACKLIST_DISABLED) {
179 RecordBlacklistSetupEvent(BLACKLIST_SETUP_DISABLED);
182 // Find the last recorded blacklist version.
183 base::string16 blacklist_version;
184 blacklist_registry_key.ReadValue(blacklist::kBeaconVersion,
185 &blacklist_version);
187 if (blacklist_version != TEXT(CHROME_VERSION_STRING)) {
188 // The blacklist hasn't been enabled for this version yet, so enable it
189 // and reset the failure count to zero.
190 LONG set_version = blacklist_registry_key.WriteValue(
191 blacklist::kBeaconVersion,
192 TEXT(CHROME_VERSION_STRING));
194 LONG set_state = blacklist_registry_key.WriteValue(
195 blacklist::kBeaconState,
196 blacklist::BLACKLIST_ENABLED);
198 blacklist_registry_key.WriteValue(blacklist::kBeaconAttemptCount,
199 static_cast<DWORD>(0));
201 // Only report the blacklist as getting setup when both registry writes
202 // succeed, since otherwise the blacklist wasn't properly setup.
203 if (set_version == ERROR_SUCCESS && set_state == ERROR_SUCCESS)
204 RecordBlacklistSetupEvent(BLACKLIST_SETUP_ENABLED);