Add the Windows.IsPinnedToTaskbar metric.

This metric records the taskbar pinned state of Chrome for the current
user. Because the code loads shell extensions into the process, this
is done on a utility process.

BUG=621662

Review-Url: https://codereview.chromium.org/2079233004
Cr-Commit-Position: refs/heads/master@{#403695}
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index 87954bb..b2bcf29 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -43,6 +43,8 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths_internal.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/common/shell_handler_win.mojom.h"
+#include "chrome/grit/generated_resources.h"
 #include "chrome/installer/setup/setup_util.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/create_reg_key_work_item.h"
@@ -55,6 +57,8 @@
 #include "chrome/installer/util/work_item_list.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/utility_process_mojo_client.h"
+#include "ui/base/l10n/l10n_util.h"
 
 using content::BrowserThread;
 
@@ -421,6 +425,41 @@
 
 OpenSystemSettingsHelper* OpenSystemSettingsHelper::instance_ = nullptr;
 
+void RecordPinnedToTaskbarProcessError(bool error) {
+  UMA_HISTOGRAM_BOOLEAN("Windows.IsPinnedToTaskbar.ProcessError", error);
+}
+
+// Record the UMA histogram when a response is received. The callback that binds
+// to this function holds a reference to the ShellHandlerClient to keep it alive
+// until invokation.
+void OnIsPinnedToTaskbarResult(
+    content::UtilityProcessMojoClient<mojom::ShellHandler>* client,
+    bool succeeded,
+    bool is_pinned_to_taskbar) {
+  // Clean up the utility process.
+  delete client;
+
+  RecordPinnedToTaskbarProcessError(false);
+
+  enum Result { NOT_PINNED, PINNED, FAILURE, NUM_RESULTS };
+
+  Result result = FAILURE;
+  if (succeeded)
+    result = is_pinned_to_taskbar ? PINNED : NOT_PINNED;
+  UMA_HISTOGRAM_ENUMERATION("Windows.IsPinnedToTaskbar", result, NUM_RESULTS);
+}
+
+// Called when a connection error happen with the shell handler process. A call
+// to this function is mutially exclusive with a call to
+// OnIsPinnedToTaskbarResult().
+void OnShellHandlerConnectionError(
+    content::UtilityProcessMojoClient<mojom::ShellHandler>* client) {
+  // Clean up the utility process.
+  delete client;
+
+  RecordPinnedToTaskbarProcessError(true);
+}
+
 }  // namespace
 
 bool SetAsDefaultBrowser() {
@@ -659,6 +698,25 @@
       base::TimeDelta::FromSeconds(kMigrateTaskbarPinsDelaySeconds));
 }
 
+void RecordIsPinnedToTaskbarHistogram() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  // The code to check if Chrome is pinned to the taskbar brings in shell
+  // extensions which can hinder stability so it is executed in a utility
+  // process.
+  content::UtilityProcessMojoClient<mojom::ShellHandler>* client =
+      new content::UtilityProcessMojoClient<mojom::ShellHandler>(
+          l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_SHELL_HANDLER_NAME));
+
+  client->set_error_callback(
+      base::Bind(&OnShellHandlerConnectionError, client));
+  client->set_disable_sandbox();
+  client->Start();
+
+  client->service()->IsPinnedToTaskbar(
+      base::Bind(&OnIsPinnedToTaskbarResult, client));
+}
+
 int MigrateShortcutsInPathInternal(const base::FilePath& chrome_exe,
                                    const base::FilePath& path) {
   DCHECK(base::win::GetVersion() >= base::win::VERSION_WIN7);