This is the cherry pick merge for the M73 branch which was approved here: http://crbug.com/926896

[Autofill Assistant] Add a histogram for drop outs.

This patch introduces a histogram to track how AA is closed or fails.
It only includes the drop out part with an initial generic "Autostart"
event for "no drop out". Another histogram for different flavors to start
AA will follow. Some of these bucket names will be refined later.

Bug: 806868
Change-Id: If97a7dde70e2be61424838c426cf076a0241e885
Reviewed-on: https://chromium-review.googlesource.com/c/1425614
Commit-Queue: Mathias Carlen <mcarlen@chromium.org>
Reviewed-by: Brian White <bcwhite@chromium.org>
Reviewed-by: Stephane Zermatten <szermatt@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#626536}(cherry picked from commit 217b627b04a4738b942fbd4bdc8d5a39b225ac1d)
Reviewed-on: https://chromium-review.googlesource.com/c/1448234
Reviewed-by: Mathias Carlen <mcarlen@chromium.org>
Cr-Commit-Position: refs/branch-heads/3683@{#107}
Cr-Branched-From: e51029943e0a38dd794b73caaf6373d5496ae783-refs/heads/master@{#625896}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
index 828ef20..058e065 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantCoordinator.java
@@ -11,6 +11,7 @@
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderModel;
+import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason;
 import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.snackbar.Snackbar;
@@ -56,6 +57,7 @@
     private final AssistantOverlayCoordinator mOverlayCoordinator;
 
     private boolean mIsShuttingDownGracefully;
+    private boolean mIsDropOutRecorded;
 
     AssistantCoordinator(ChromeActivity activity, WebContents webContents, Delegate delegate) {
         mActivity = activity;
@@ -80,7 +82,11 @@
     /**
      * Shut down the Autofill Assistant immediately, without showing a message.
      */
-    public void shutdownImmediately() {
+    public void shutdownImmediately(@DropOutReason int reason) {
+        if (!mIsDropOutRecorded) {
+            AutofillAssistantMetrics.recordDropOut(reason);
+            mIsDropOutRecorded = true;
+        }
         detachAssistantView();
         mOverlayCoordinator.destroy();
         mDelegate.stop();
@@ -92,7 +98,7 @@
      * the status message with a generic error message iff {@code showGiveUpMessage} is true.
      */
     // TODO(crbug.com/806868): Move this method to native.
-    public void gracefulShutdown(boolean showGiveUpMessage) {
+    public void gracefulShutdown(boolean showGiveUpMessage, @DropOutReason int reason) {
         mIsShuttingDownGracefully = true;
 
         // Make sure bottom bar is expanded.
@@ -108,14 +114,15 @@
             mModel.getHeaderModel().set(AssistantHeaderModel.STATUS_MESSAGE,
                     mActivity.getString(R.string.autofill_assistant_give_up));
         }
-        ThreadUtils.postOnUiThreadDelayed(this::shutdownImmediately, GRACEFUL_SHUTDOWN_DELAY_MS);
+        ThreadUtils.postOnUiThreadDelayed(
+                () -> shutdownImmediately(reason), GRACEFUL_SHUTDOWN_DELAY_MS);
     }
 
     /**
      * Shut down the Autofill Assistant and close the current Chrome tab.
      */
     public void close() {
-        shutdownImmediately();
+        shutdownImmediately(DropOutReason.CUSTOM_TAB_CLOSED);
         mActivity.finish();
     }
 
@@ -134,7 +141,7 @@
         AssistantOnboardingCoordinator.show(mActivity, mBottomBarCoordinator.getView())
                 .then(accepted -> {
                     if (!accepted) {
-                        shutdownImmediately();
+                        shutdownImmediately(DropOutReason.DECLINED);
                         return;
                     }
 
@@ -175,9 +182,9 @@
      * Dismiss the assistant view and show a cancellable snackbar alerting the user that the
      * Autofill assistant is shutting down.
      */
-    public void dismissAndShowSnackbar(String message) {
+    public void dismissAndShowSnackbar(String message, @DropOutReason int reason) {
         if (mIsShuttingDownGracefully) {
-            shutdownImmediately();
+            shutdownImmediately(reason);
             return;
         }
 
@@ -194,7 +201,7 @@
 
                                     @Override
                                     public void onDismissNoAction(Object actionData) {
-                                        shutdownImmediately();
+                                        shutdownImmediately(reason);
                                     }
                                 },
                                 Snackbar.TYPE_ACTION, Snackbar.UMA_AUTOFILL_ASSISTANT_STOP_UNDO)
@@ -204,8 +211,8 @@
         mActivity.getSnackbarManager().showSnackbar(snackBar);
     }
 
-    private void dismissAndShowSnackbar(int message) {
-        dismissAndShowSnackbar(mActivity.getString(message));
+    private void dismissAndShowSnackbar(int message, @DropOutReason int reason) {
+        dismissAndShowSnackbar(mActivity.getString(message), reason);
     }
 
     /**
@@ -221,7 +228,8 @@
 
     @Override
     public void onUnexpectedTaps() {
-        dismissAndShowSnackbar(R.string.autofill_assistant_maybe_give_up);
+        dismissAndShowSnackbar(
+                R.string.autofill_assistant_maybe_give_up, DropOutReason.OVERLAY_STOP);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
index a2304a5..e0a647e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -13,6 +13,7 @@
 import org.chromium.base.Callback;
 import org.chromium.chrome.browser.ActivityTabProvider;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.util.IntentUtils;
 
@@ -57,6 +58,8 @@
 
     /** Starts Autofill Assistant on the given {@code activity}. */
     public static void start(ChromeActivity activity) {
+        // Have an "attempted starts" baseline for the drop out histogram.
+        AutofillAssistantMetrics.recordDropOut(DropOutReason.AA_START);
         if (canStart(activity.getInitialIntent())) {
             getTab(activity, tab -> startNow(activity, tab));
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
new file mode 100644
index 0000000..513560e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
@@ -0,0 +1,27 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill_assistant;
+
+import org.chromium.base.metrics.CachedMetrics.EnumeratedHistogramSample;
+import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason;
+
+/**
+ * Records user actions and histograms related to Autofill Assistant.
+ *
+ * The |DropOutReason| enum is auto generated from
+ * components/autofill_assistant/browser/metrics.h.
+ */
+/* package */ class AutofillAssistantMetrics {
+    private static final EnumeratedHistogramSample ENUMERATED_DROP_OUT_REASON =
+            new EnumeratedHistogramSample(
+                    "Android.AutofillAssistant.DropOutReason", DropOutReason.NUM_ENTRIES);
+
+    /**
+     * Records the reason for a drop out.
+     */
+    /* package */ static void recordDropOut(@DropOutReason int reason) {
+        ENUMERATED_DROP_OUT_REASON.record(reason);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
index 23bcbf4..47d98c2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -11,6 +11,7 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
+import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason;
 import org.chromium.chrome.browser.autofill_assistant.payment.AutofillAssistantPaymentRequest.SelectedPaymentInformation;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -65,7 +66,7 @@
             public void onActivityAttachmentChanged(Tab tab, boolean isAttached) {
                 if (!isAttached) {
                     activityTab.removeObserver(this);
-                    mCoordinator.shutdownImmediately();
+                    mCoordinator.shutdownImmediately(DropOutReason.TAB_DETACHED);
                 }
             }
         });
@@ -78,7 +79,8 @@
                 // Shutdown the Autofill Assistant if the user switches to another tab.
                 if (!activityTab.equals(tab)) {
                     currentTabModel.removeObserver(this);
-                    mCoordinator.gracefulShutdown(/* showGiveUpMessage= */ true);
+                    mCoordinator.gracefulShutdown(
+                            /* showGiveUpMessage= */ true, DropOutReason.TAB_CHANGED);
                 }
             }
         });
@@ -149,13 +151,13 @@
     }
 
     @CalledByNative
-    private void onShutdown() {
-        mCoordinator.shutdownImmediately();
+    private void onShutdown(@DropOutReason int reason) {
+        mCoordinator.shutdownImmediately(reason);
     }
 
     @CalledByNative
-    private void onShutdownGracefully() {
-        mCoordinator.gracefulShutdown(/* showGiveUpMessage= */ false);
+    private void onShutdownGracefully(@DropOutReason int reason) {
+        mCoordinator.gracefulShutdown(/* showGiveUpMessage= */ false, reason);
     }
 
     @CalledByNative
@@ -193,7 +195,7 @@
 
     private void onRequestPaymentInformationFailed(Exception unusedException) {
         mCoordinator.getBottomBarCoordinator().allowSwipingBottomSheet(true);
-        mCoordinator.gracefulShutdown(/* showGiveUpMessage= */ true);
+        mCoordinator.gracefulShutdown(/* showGiveUpMessage= */ true, DropOutReason.PR_FAILED);
     }
 
     @CalledByNative
@@ -212,8 +214,8 @@
     }
 
     @CalledByNative
-    private void dismissAndShowSnackbar(String message) {
-        mCoordinator.dismissAndShowSnackbar(message);
+    private void dismissAndShowSnackbar(String message, @DropOutReason int reason) {
+        mCoordinator.dismissAndShowSnackbar(message, reason);
     }
 
     // Native methods.
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 8761b75..65cb438 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -142,6 +142,7 @@
   "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantOverlayCoordinator.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java",
+  "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java",
   "java/src/org/chromium/chrome/browser/autofill_assistant/FeedbackContext.java",
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index 8224b99..198657e 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -85,6 +85,12 @@
       weak_ptr_factory_(this) {}
 
 ClientAndroid::~ClientAndroid() {
+  if (controller_ != nullptr) {
+    // In the case of an unexpected closing of the activity or tab, controller_
+    // will not yet have been cleaned up (since that happens when a web
+    // contents object gets destroyed).
+    Metrics::RecordDropOut(Metrics::CONTENT_DESTROYED);
+  }
   Java_AutofillAssistantClient_clearNativePtr(AttachCurrentThread(),
                                               java_object_);
 }
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 031e714..03f45242 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -24,6 +24,7 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill_assistant/browser/controller.h"
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/rectf.h"
 #include "components/signin/core/browser/account_info.h"
 #include "components/strings/grit/components_strings.h"
@@ -177,8 +178,10 @@
 }
 
 void UiControllerAndroid::ShutdownGracefully() {
+  DCHECK(ui_delegate_->GetDropOutReason() != Metrics::AA_START);
   Java_AutofillAssistantUiController_onShutdownGracefully(
-      AttachCurrentThread(), java_autofill_assistant_ui_controller_);
+      AttachCurrentThread(), java_autofill_assistant_ui_controller_,
+      ui_delegate_->GetDropOutReason());
 }
 
 void UiControllerAndroid::SetProgressPulsingEnabled(bool enabled) {
@@ -200,7 +203,8 @@
   Java_AutofillAssistantUiController_dismissAndShowSnackbar(
       env, java_autofill_assistant_ui_controller_,
       base::android::ConvertUTF8ToJavaString(
-          env, l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_STOPPED)));
+          env, l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_STOPPED)),
+      Metrics::SHEET_CLOSED);
 }
 
 std::string UiControllerAndroid::GetDebugContext() {
@@ -260,9 +264,9 @@
       env, java_autofill_assistant_ui_controller_, on_accept);
 }
 
-void UiControllerAndroid::Shutdown() {
+void UiControllerAndroid::Shutdown(Metrics::DropOutReason reason) {
   Java_AutofillAssistantUiController_onShutdown(
-      AttachCurrentThread(), java_autofill_assistant_ui_controller_);
+      AttachCurrentThread(), java_autofill_assistant_ui_controller_, reason);
 }
 
 void UiControllerAndroid::Close() {
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index d4e198e..15ca21e 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -15,6 +15,7 @@
 #include "chrome/browser/android/autofill_assistant/assistant_header_delegate.h"
 #include "components/autofill_assistant/browser/client.h"
 #include "components/autofill_assistant/browser/details.h"
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/ui_controller.h"
 
 namespace autofill_assistant {
@@ -38,7 +39,7 @@
   // Overrides UiController:
   void OnStateChanged(AutofillAssistantState new_state) override;
   void OnStatusMessageChanged(const std::string& message) override;
-  void Shutdown() override;
+  void Shutdown(Metrics::DropOutReason reason) override;
   void Close() override;
   void SetChips(std::unique_ptr<std::vector<Chip>> chips) override;
   void ClearChips() override;
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index 653504d6..9e69040 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -22,6 +22,7 @@
 java_cpp_enum("autofill_assistant_enums_java") {
   sources = [
     "chip.h",
+    "metrics.h",
   ]
 }
 
@@ -80,6 +81,8 @@
     "details.h",
     "element_area.cc",
     "element_area.h",
+    "metrics.cc",
+    "metrics.h",
     "payment_information.h",
     "protocol_utils.cc",
     "protocol_utils.h",
diff --git a/components/autofill_assistant/browser/actions/autofill_action.cc b/components/autofill_assistant/browser/actions/autofill_action.cc
index 1567b79..e5573c3 100644
--- a/components/autofill_assistant/browser/actions/autofill_action.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action.cc
@@ -19,7 +19,6 @@
 
 namespace autofill_assistant {
 
-
 AutofillAction::AutofillAction(const ActionProto& proto)
     : Action(proto), weak_ptr_factory_(this) {
   if (proto.has_use_address()) {
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 36ee39f..e26c580 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/values.h"
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/protocol_utils.h"
 #include "components/autofill_assistant/browser/ui_controller.h"
 #include "components/strings/grit/components_strings.h"
@@ -205,6 +206,7 @@
     should_fail_after_checking_scripts_ = false;
     SetStatusMessage(
         l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR));
+    stop_reason_ = Metrics::AUTOSTART_TIMEOUT;
     EnterState(AutofillAssistantState::STOPPED);
     return;
   }
@@ -265,6 +267,7 @@
     LOG(ERROR) << "Failed to execute script " << script_path;
     SetStatusMessage(
         l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_DEFAULT_ERROR));
+    stop_reason_ = Metrics::SCRIPT_FAILED;
     EnterState(AutofillAssistantState::STOPPED);
     return;
   }
@@ -279,15 +282,21 @@
 
   switch (result.at_end) {
     case ScriptExecutor::SHUTDOWN:
+      GetUiController()->Shutdown(Metrics::SCRIPT_SHUTDOWN);
+      return;
     case ScriptExecutor::TERMINATE:
       // TODO(crbug.com/806868): Distinguish shutdown from terminate: Users
       // should be allowed to undo shutdown, but not terminate.
-
-      GetUiController()->Shutdown();  // indirectly deletes this
+      //
+      // This is coming from a client Stop() to clean up and we already counted
+      // it as a stop event. The code here is only executed if no script was
+      // running, so there may be some double counting.
+      GetUiController()->Shutdown(Metrics::SAFETY_NET_TERMINATE);
       return;
 
     case ScriptExecutor::SHUTDOWN_GRACEFULLY:
       GetWebController()->ClearCookie();
+      stop_reason_ = Metrics::SCRIPT_SHUTDOWN;
       EnterState(AutofillAssistantState::STOPPED);
       return;
 
@@ -311,8 +320,9 @@
   GetOrCheckScripts(web_contents()->GetLastCommittedURL());
 }
 
-void Controller::GiveUp() {
+void Controller::GiveUp(Metrics::DropOutReason reason) {
   SetStatusMessage(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP));
+  stop_reason_ = reason;
   EnterState(AutofillAssistantState::STOPPED);
 }
 
@@ -460,13 +470,17 @@
   return output_js;
 }
 
+Metrics::DropOutReason Controller::GetDropOutReason() const {
+  return stop_reason_;
+}
+
 void Controller::OnNoRunnableScriptsAnymore() {
   if (script_tracker()->running())
     return;
 
   // We're navigated to a page that has no scripts or the scripts have reached a
   // state from which they cannot recover through a DOM change.
-  GiveUp();
+  GiveUp(Metrics::NO_SCRIPTS);
   return;
 }
 
@@ -529,7 +543,7 @@
 }
 
 void Controller::DidAttachInterstitialPage() {
-  GetUiController()->Shutdown();
+  GetUiController()->Shutdown(Metrics::INTERSTITIAL_PAGE);
 }
 
 void Controller::DidFinishLoad(content::RenderFrameHost* render_frame_host,
@@ -568,7 +582,7 @@
     // The action can define a touchable element area that prevents navigation.
     if (!script_tracker_ || !script_tracker()->running() ||
         touchable_element_area()->HasElements()) {
-      GiveUp();
+      GiveUp(Metrics::NAVIGATION);
     }
   }
 }
@@ -578,7 +592,7 @@
 }
 
 void Controller::RenderProcessGone(base::TerminationStatus status) {
-  GetUiController()->Shutdown();
+  GetUiController()->Shutdown(Metrics::RENDER_PROCESS_GONE);
 }
 
 void Controller::LoadProgressChanged(content::WebContents* source,
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 36fa10e..0bf5641 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -14,6 +14,7 @@
 #include "components/autofill_assistant/browser/client.h"
 #include "components/autofill_assistant/browser/client_memory.h"
 #include "components/autofill_assistant/browser/element_area.h"
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/script.h"
 #include "components/autofill_assistant/browser/script_executor_delegate.h"
 #include "components/autofill_assistant/browser/script_tracker.h"
@@ -102,7 +103,7 @@
   void StartPeriodicScriptChecks();
   void StopPeriodicScriptChecks();
   void OnPeriodicScriptCheck();
-  void GiveUp();
+  void GiveUp(Metrics::DropOutReason reason);
 
   // Runs autostart scripts from |runnable_scripts|, if the conditions are
   // right. Returns true if a script was auto-started.
@@ -128,6 +129,7 @@
   void OnUserInteractionInsideTouchableArea() override;
   const Details* GetDetails() const override;
   std::string GetDebugContext() override;
+  Metrics::DropOutReason GetDropOutReason() const override;
 
   // Overrides ScriptTracker::Listener:
   void OnNoRunnableScriptsAnymore() override;
@@ -197,6 +199,9 @@
   // Flag indicates whether it is ready to fetch and execute scripts.
   bool started_ = false;
 
+  // Drop out reason set when the controller enters a STOPPED state.
+  Metrics::DropOutReason stop_reason_ = Metrics::AA_START;
+
   // Tracks scripts and script execution. It's kept at the end, as it tend to
   // depend on everything the controller support, through script and script
   // actions.
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 82a6d9d..aea610c 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -266,7 +266,7 @@
   EXPECT_CALL(*mock_service_, OnGetNextActions(_, _, _, _))
       .WillOnce(RunOnceCallback<3>(true, ""));
 
-  EXPECT_CALL(mock_ui_controller_, Shutdown());
+  EXPECT_CALL(mock_ui_controller_, Shutdown(_));
 
   ExecuteScript("stop");
 }
diff --git a/components/autofill_assistant/browser/metrics.cc b/components/autofill_assistant/browser/metrics.cc
new file mode 100644
index 0000000..4be484a
--- /dev/null
+++ b/components/autofill_assistant/browser/metrics.cc
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill_assistant/browser/metrics.h"
+
+#include "base/metrics/histogram_macros.h"
+
+namespace autofill_assistant {
+
+namespace {
+const char* const kDropOutEnumName = "Android.AutofillAssistant.DropOutReason";
+}  // namespace
+
+// static
+void Metrics::RecordDropOut(DropOutReason reason) {
+  DCHECK_LE(reason, DropOutReason::NUM_ENTRIES);
+  UMA_HISTOGRAM_ENUMERATION(kDropOutEnumName, reason, NUM_ENTRIES);
+}
+
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/metrics.h b/components/autofill_assistant/browser/metrics.h
new file mode 100644
index 0000000..f8fbf27
--- /dev/null
+++ b/components/autofill_assistant/browser/metrics.h
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_METRICS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_METRICS_H_
+
+namespace autofill_assistant {
+
+// A class to generate Autofill Assistant related histograms.
+class Metrics {
+ public:
+  // The different ways that autofill assistant can stop.
+  //
+  // GENERATED_JAVA_ENUM_PACKAGE: (
+  // org.chromium.chrome.browser.autofill_assistant.metrics)
+  // GENERATED_JAVA_CLASS_NAME_OVERRIDE: DropOutReason
+  enum DropOutReason {
+    AA_START = 0,
+    AUTOSTART_TIMEOUT = 1,
+    NO_SCRIPTS = 2,
+    CUSTOM_TAB_CLOSED = 3,
+    DECLINED = 4,
+    SHEET_CLOSED = 5,
+    SCRIPT_FAILED = 6,
+    NAVIGATION = 7,
+    OVERLAY_STOP = 8,
+    PR_FAILED = 9,
+    CONTENT_DESTROYED = 10,
+    RENDER_PROCESS_GONE = 11,
+    INTERSTITIAL_PAGE = 12,
+    SCRIPT_SHUTDOWN = 13,
+    SAFETY_NET_TERMINATE = 14,  // This is a "should never happen" entry.
+    TAB_DETACHED = 15,
+    TAB_CHANGED = 16,
+    NUM_ENTRIES = 17,
+  };
+
+  static void RecordDropOut(DropOutReason reason);
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_METRICS_H_
diff --git a/components/autofill_assistant/browser/mock_ui_controller.h b/components/autofill_assistant/browser/mock_ui_controller.h
index 2e21e9b..9283a2f 100644
--- a/components/autofill_assistant/browser/mock_ui_controller.h
+++ b/components/autofill_assistant/browser/mock_ui_controller.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/script.h"
 #include "components/autofill_assistant/browser/ui_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -23,7 +24,7 @@
 
   MOCK_METHOD1(OnStatusMessageChanged, void(const std::string& message));
   MOCK_METHOD1(OnStateChanged, void(AutofillAssistantState));
-  MOCK_METHOD0(Shutdown, void());
+  MOCK_METHOD1(Shutdown, void(Metrics::DropOutReason));
   MOCK_METHOD0(Close, void());
   MOCK_METHOD1(SetChips, void(std::unique_ptr<std::vector<Chip>> chips));
   MOCK_METHOD0(ClearChips, void());
@@ -41,6 +42,7 @@
                void(bool enabled, const std::vector<RectF>& areas));
   MOCK_CONST_METHOD0(Terminate, bool());
   MOCK_METHOD0(ExpandBottomSheet, void());
+  MOCK_CONST_METHOD0(GetDropOutReason, Metrics::DropOutReason());
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service.cc b/components/autofill_assistant/browser/service.cc
index ec55dc1..b9cfb7e 100644
--- a/components/autofill_assistant/browser/service.cc
+++ b/components/autofill_assistant/browser/service.cc
@@ -228,6 +228,8 @@
                << loader_instance->loader->NetError()
                << " response_code=" << response_code << " message="
                << (response_body == nullptr ? "" : *response_body);
+    // TODO(crbug.com/806868): Pass an enum to be able to distinguish errors
+    // downstream. Also introduce a metric for this.
     std::move(loader_instance->callback).Run(false, response_body_str);
     return;
   }
diff --git a/components/autofill_assistant/browser/ui_controller.h b/components/autofill_assistant/browser/ui_controller.h
index a51eb46..788eea7 100644
--- a/components/autofill_assistant/browser/ui_controller.h
+++ b/components/autofill_assistant/browser/ui_controller.h
@@ -12,6 +12,7 @@
 #include "base/callback_forward.h"
 #include "components/autofill_assistant/browser/chip.h"
 #include "components/autofill_assistant/browser/details.h"
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/payment_information.h"
 #include "components/autofill_assistant/browser/script.h"
 #include "components/autofill_assistant/browser/state.h"
@@ -34,7 +35,7 @@
   // Shuts down Autofill Assistant: hide the UI and frees any associated state.
   //
   // Warning: this indirectly deletes the caller.
-  virtual void Shutdown() = 0;
+  virtual void Shutdown(Metrics::DropOutReason reason) = 0;
 
   // Shuts down Autofill Assistant and closes Chrome.
   virtual void Close() = 0;
diff --git a/components/autofill_assistant/browser/ui_delegate.h b/components/autofill_assistant/browser/ui_delegate.h
index 4c04d4e..62e67bd 100644
--- a/components/autofill_assistant/browser/ui_delegate.h
+++ b/components/autofill_assistant/browser/ui_delegate.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "components/autofill_assistant/browser/metrics.h"
 #include "components/autofill_assistant/browser/state.h"
 
 namespace autofill_assistant {
@@ -38,6 +39,9 @@
   // Returns the current contextual information. May be null if empty.
   virtual const Details* GetDetails() const = 0;
 
+  // Returns the drop out reason for the last state transition to STOPPED.
+  virtual Metrics::DropOutReason GetDropOutReason() const = 0;
+
  protected:
   UiDelegate() = default;
 };
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 74c8f34..03c7022 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2637,6 +2637,26 @@
   <int value="1" label="Suggestion Selected"/>
 </enum>
 
+<enum name="AutofillAssistantDropOutReason">
+  <int value="0" label="Autofill Assistant started"/>
+  <int value="1" label="Autostart timed out"/>
+  <int value="2" label="No scripts available"/>
+  <int value="3" label="Custom tab closed"/>
+  <int value="4" label="User declined"/>
+  <int value="5" label="Sheet closed"/>
+  <int value="6" label="Script failed"/>
+  <int value="7" label="User navigation"/>
+  <int value="8" label="Unexpected taps on overlay"/>
+  <int value="9" label="Request payment info failed"/>
+  <int value="10" label="Web contents destroyed"/>
+  <int value="11" label="Render process gone"/>
+  <int value="12" label="Interstitial page attached"/>
+  <int value="13" label="Script initiated shutdown"/>
+  <int value="14" label="Safety net termination"/>
+  <int value="15" label="Tab detached"/>
+  <int value="16" label="Tab changed"/>
+</enum>
+
 <enum name="AutofillCardholderNameFixFlowPromptEvent">
   <int value="0" label="Shown"/>
   <int value="1" label="Accepted"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 10db1a0..c8270e6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -1310,6 +1310,18 @@
   </summary>
 </histogram>
 
+<histogram name="Android.AutofillAssistant.DropOutReason"
+    enum="AutofillAssistantDropOutReason" expires_after="2020-01-25">
+  <owner>mcarlen@chromium.org</owner>
+  <summary>
+    Reports the drop out reason of an Autofill Assistant script. It is recorded
+    when Autofill Assistant is shut down or terminated. The AA_START value is
+    used as a baseline and counts the number of attempted starts of Autofill
+    Assistant flows. The sum of all drop out reasons should be the same as the
+    number of attempted starts (i.e. AA_START).
+  </summary>
+</histogram>
+
 <histogram name="Android.BackgroundTaskScheduler.TaskCanceled"
     enum="BackgroundTaskId">
   <owner>fgorski@chromium.org</owner>