Commit af6d122a authored by David Roger's avatar David Roger Committed by Chromium LUCI CQ

[profiles] DiceInterceptedSessionStartupHelper calls multilogin directly

This CL changes the way DiceInterceptedSessionStartupHelper adds the
account on the web.
Previously it was mostly waiting for the reconcilor to trigger, and
making sure that the process is not stuck (by forcing calls to list
accounts).

The new behavior is more proactive: when the profile is new, it blocks
the reconcilor and forces a call to multilogin directly.
The advantages are:
- it is easier to control and hopefully it should be less brittle.
- it should be faster:
  * the previous flow was doing an extra /ListAccounts call after the
    reconciliation, which is now removed
  * the previous flow was using MergeSession while the new flow uses
    multilogin, which should be faster on desktop (no need to fetch an
    access token)

When the profile is not new, it's not possible to simply use multilogin,
as there may already be accounts in the profile. The reconcilor is still
used in this case, as it has the logic to handle this.

Note: it would be possible to use MergeSession instead of Multilogin, as
this would work for all profiles (including existing profiles). However
MergeSession is now discouraged and thus we avoid adding a new usage
here.

This CL also improves histograms.

Bug: 1151313
Change-Id: I9e0f6034abd845047226a3b592ce9a1dabf0c7d2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2600909
Commit-Queue: David Roger <droger@chromium.org>
Commit-Queue: Alex Ilin <alexilin@chromium.org>
Auto-Submit: David Roger <droger@chromium.org>
Reviewed-by: default avatarAlex Ilin <alexilin@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#840690}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2612845
Cr-Commit-Position: refs/heads/master@{#840995}
parent b2eeb435
...@@ -17,9 +17,12 @@ ...@@ -17,9 +17,12 @@
#include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/common/webui_url_constants.h" #include "chrome/common/webui_url_constants.h"
#include "components/signin/public/base/multilogin_parameters.h"
#include "components/signin/public/identity_manager/accounts_cookie_mutator.h" #include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
#include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h" #include "components/signin/public/identity_manager/accounts_in_cookie_jar_info.h"
#include "components/signin/public/identity_manager/set_accounts_in_cookie_result.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/google_service_auth_error.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -37,13 +40,23 @@ bool CookieInfoContains(const signin::AccountsInCookieJarInfo& cookie_info, ...@@ -37,13 +40,23 @@ bool CookieInfoContains(const signin::AccountsInCookieJarInfo& cookie_info,
}) != accounts.end(); }) != accounts.end();
} }
void RecordSessionStartupDuration(const std::string& histogram_name,
base::TimeDelta duration) {
base::UmaHistogramCustomTimes(histogram_name, duration,
/*min=*/base::TimeDelta::FromMilliseconds(1),
/*max=*/base::TimeDelta::FromSeconds(30), 50);
}
} // namespace } // namespace
DiceInterceptedSessionStartupHelper::DiceInterceptedSessionStartupHelper( DiceInterceptedSessionStartupHelper::DiceInterceptedSessionStartupHelper(
Profile* profile, Profile* profile,
bool is_new_profile,
CoreAccountId account_id, CoreAccountId account_id,
content::WebContents* tab_to_move) content::WebContents* tab_to_move)
: profile_(profile), account_id_(account_id) { : profile_(profile),
use_multilogin_(is_new_profile),
account_id_(account_id) {
Observe(tab_to_move); Observe(tab_to_move);
} }
...@@ -64,24 +77,26 @@ void DiceInterceptedSessionStartupHelper::Startup(base::OnceClosure callback) { ...@@ -64,24 +77,26 @@ void DiceInterceptedSessionStartupHelper::Startup(base::OnceClosure callback) {
identity_manager->GetAccountsInCookieJar(); identity_manager->GetAccountsInCookieJar();
if (cookie_info.accounts_are_fresh && if (cookie_info.accounts_are_fresh &&
CookieInfoContains(cookie_info, account_id_)) { CookieInfoContains(cookie_info, account_id_)) {
MoveTab(); MoveTab(use_multilogin_ ? Result::kMultiloginNothingToDo
: Result::kReconcilorNothingToDo);
} else { } else {
// TODO(https://crbug.com/1051864): cookie notifications are not triggered // Set the timeout.
// when the account is added by the reconcilor. Observe the reconcilor and
// re-trigger the cookie update when it completes.
reconcilor_observer_.Observe(
AccountReconcilorFactory::GetForProfile(profile_));
identity_manager->GetAccountsCookieMutator()->TriggerCookieJarUpdate();
accounts_in_cookie_observer_.Observe(identity_manager);
on_cookie_update_timeout_.Reset(base::BindOnce( on_cookie_update_timeout_.Reset(base::BindOnce(
&DiceInterceptedSessionStartupHelper::MoveTab, base::Unretained(this))); &DiceInterceptedSessionStartupHelper::MoveTab, base::Unretained(this),
use_multilogin_ ? Result::kMultiloginTimeout
: Result::kReconcilorTimeout));
// Adding accounts to the cookies can be an expensive operation. In // Adding accounts to the cookies can be an expensive operation. In
// particular the ExternalCCResult fetch may time out after multiple seconds // particular the ExternalCCResult fetch may time out after multiple seconds
// (see kExternalCCResultTimeoutSeconds and https://crbug.com/750316#c37). // (see kExternalCCResultTimeoutSeconds and https://crbug.com/750316#c37).
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, on_cookie_update_timeout_.callback(), FROM_HERE, on_cookie_update_timeout_.callback(),
base::TimeDelta::FromSeconds(12)); base::TimeDelta::FromSeconds(12));
accounts_in_cookie_observer_.Observe(identity_manager);
if (use_multilogin_)
StartupMultilogin(identity_manager);
else
StartupReconcilor(identity_manager);
} }
} }
...@@ -94,11 +109,14 @@ void DiceInterceptedSessionStartupHelper::OnAccountsInCookieUpdated( ...@@ -94,11 +109,14 @@ void DiceInterceptedSessionStartupHelper::OnAccountsInCookieUpdated(
return; return;
if (!CookieInfoContains(accounts_in_cookie_jar_info, account_id_)) if (!CookieInfoContains(accounts_in_cookie_jar_info, account_id_))
return; return;
MoveTab();
MoveTab(use_multilogin_ ? Result::kMultiloginOtherSuccess
: Result::kReconcilorSuccess);
} }
void DiceInterceptedSessionStartupHelper::OnStateChanged( void DiceInterceptedSessionStartupHelper::OnStateChanged(
signin_metrics::AccountReconcilorState state) { signin_metrics::AccountReconcilorState state) {
DCHECK(!use_multilogin_);
if (state == signin_metrics::ACCOUNT_RECONCILOR_ERROR) { if (state == signin_metrics::ACCOUNT_RECONCILOR_ERROR) {
reconcile_error_encountered_ = true; reconcile_error_encountered_ = true;
return; return;
...@@ -118,15 +136,57 @@ void DiceInterceptedSessionStartupHelper::OnStateChanged( ...@@ -118,15 +136,57 @@ void DiceInterceptedSessionStartupHelper::OnStateChanged(
} }
} }
void DiceInterceptedSessionStartupHelper::MoveTab() { void DiceInterceptedSessionStartupHelper::StartupMultilogin(
signin::IdentityManager* identity_manager) {
// Lock the reconcilor to avoid making multiple multilogin calls.
reconcilor_lock_ = std::make_unique<AccountReconcilor::Lock>(
AccountReconcilorFactory::GetForProfile(profile_));
// Start the multilogin call.
signin::MultiloginParameters params = {
/*mode=*/gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER,
/*accounts_to_send=*/{account_id_}};
identity_manager->GetAccountsCookieMutator()->SetAccountsInCookie(
params, gaia::GaiaSource::kChrome,
base::BindOnce(
&DiceInterceptedSessionStartupHelper::OnSetAccountInCookieCompleted,
weak_factory_.GetWeakPtr()));
}
void DiceInterceptedSessionStartupHelper::StartupReconcilor(
signin::IdentityManager* identity_manager) {
// TODO(https://crbug.com/1051864): cookie notifications are not triggered
// when the account is added by the reconcilor. Observe the reconcilor and
// re-trigger the cookie update when it completes.
reconcilor_observer_.Observe(
AccountReconcilorFactory::GetForProfile(profile_));
identity_manager->GetAccountsCookieMutator()->TriggerCookieJarUpdate();
}
void DiceInterceptedSessionStartupHelper::OnSetAccountInCookieCompleted(
signin::SetAccountsInCookieResult result) {
DCHECK(use_multilogin_);
Result session_startup_result = Result::kMultiloginOtherSuccess;
switch (result) {
case signin::SetAccountsInCookieResult::kSuccess:
session_startup_result = Result::kMultiloginSuccess;
break;
case signin::SetAccountsInCookieResult::kTransientError:
session_startup_result = Result::kMultiloginTransientError;
break;
case signin::SetAccountsInCookieResult::kPersistentError:
session_startup_result = Result::kMultiloginPersistentError;
break;
}
MoveTab(session_startup_result);
}
void DiceInterceptedSessionStartupHelper::MoveTab(Result result) {
accounts_in_cookie_observer_.Reset(); accounts_in_cookie_observer_.Reset();
reconcilor_observer_.Reset(); reconcilor_observer_.Reset();
on_cookie_update_timeout_.Cancel(); on_cookie_update_timeout_.Cancel();
reconcilor_lock_.reset();
// TODO(https://crbug.com/1151313): Remove this histogram when the cause
// for the timeouts is understood.
base::UmaHistogramBoolean("Signin.Intercept.SessionStartupReconcileError",
reconcile_error_encountered_);
GURL url_to_open = GURL(chrome::kChromeUINewTabURL); GURL url_to_open = GURL(chrome::kChromeUINewTabURL);
// If the intercepted web contents is still alive, close it now. // If the intercepted web contents is still alive, close it now.
...@@ -140,8 +200,20 @@ void DiceInterceptedSessionStartupHelper::MoveTab() { ...@@ -140,8 +200,20 @@ void DiceInterceptedSessionStartupHelper::MoveTab() {
ui::PAGE_TRANSITION_AUTO_BOOKMARK); ui::PAGE_TRANSITION_AUTO_BOOKMARK);
Navigate(&params); Navigate(&params);
base::UmaHistogramTimes("Signin.Intercept.SessionStartupDuration", base::UmaHistogramEnumeration("Signin.Intercept.SessionStartupResult",
base::TimeTicks::Now() - session_startup_time_); result);
base::TimeDelta duration = base::TimeTicks::Now() - session_startup_time_;
if (use_multilogin_) {
RecordSessionStartupDuration(
"Signin.Intercept.SessionStartupDuration.Multilogin", duration);
} else {
RecordSessionStartupDuration(
"Signin.Intercept.SessionStartupDuration.Reconcilor", duration);
// TODO(https://crbug.com/1151313): Remove this histogram when the cause
// for the timeouts is understood.
base::UmaHistogramBoolean("Signin.Intercept.SessionStartupReconcileError",
reconcile_error_encountered_);
}
if (callback_) if (callback_)
std::move(callback_).Run(); std::move(callback_).Run();
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/cancelable_callback.h" #include "base/cancelable_callback.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h" #include "base/scoped_observation.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/signin/core/browser/account_reconcilor.h" #include "components/signin/core/browser/account_reconcilor.h"
...@@ -20,6 +21,8 @@ class WebContents; ...@@ -20,6 +21,8 @@ class WebContents;
namespace signin { namespace signin {
struct AccountsInCookieJarInfo; struct AccountsInCookieJarInfo;
class IdentityManager;
enum class SetAccountsInCookieResult;
} }
class GoogleServiceAuthError; class GoogleServiceAuthError;
...@@ -35,12 +38,28 @@ class DiceInterceptedSessionStartupHelper ...@@ -35,12 +38,28 @@ class DiceInterceptedSessionStartupHelper
public signin::IdentityManager::Observer, public signin::IdentityManager::Observer,
public AccountReconcilor::Observer { public AccountReconcilor::Observer {
public: public:
// Used in UMA histograms, do not reorder or remove values.
enum class Result {
kReconcilorNothingToDo = 0,
kMultiloginNothingToDo = 1,
kReconcilorSuccess = 2, // The account was added by the reconcilor.
kMultiloginSuccess = 3, // The account was added by this object.
kMultiloginOtherSuccess = 4, // The account was added by something else.
kMultiloginTimeout = 5,
kReconcilorTimeout = 6,
kMultiloginTransientError = 7,
kMultiloginPersistentError = 8,
kMaxValue = kMultiloginPersistentError
};
// |profile| is the new profile that was created after signin interception. // |profile| is the new profile that was created after signin interception.
// |account_id| is the main account for the profile, it's already in the // |account_id| is the main account for the profile, it's already in the
// profile. // profile.
// |tab_to_move| is the tab where the interception happened, in the source // |tab_to_move| is the tab where the interception happened, in the source
// profile. // profile.
DiceInterceptedSessionStartupHelper(Profile* profile, DiceInterceptedSessionStartupHelper(Profile* profile,
bool is_new_profile,
CoreAccountId account_id, CoreAccountId account_id,
content::WebContents* tab_to_move); content::WebContents* tab_to_move);
...@@ -63,11 +82,22 @@ class DiceInterceptedSessionStartupHelper ...@@ -63,11 +82,22 @@ class DiceInterceptedSessionStartupHelper
void OnStateChanged(signin_metrics::AccountReconcilorState state) override; void OnStateChanged(signin_metrics::AccountReconcilorState state) override;
private: private:
// For new profiles, the account is added directly using multilogin.
void StartupMultilogin(signin::IdentityManager* identity_manager);
// For existing profiles, simply wait for the reconcilor to update the
// accounts.
void StartupReconcilor(signin::IdentityManager* identity_manager);
// Called when multilogin completes.
void OnSetAccountInCookieCompleted(signin::SetAccountsInCookieResult result);
// Creates a browser with a new tab, and closes the intercepted tab if it's // Creates a browser with a new tab, and closes the intercepted tab if it's
// still open. // still open.
void MoveTab(); void MoveTab(Result result);
Profile* const profile_; Profile* const profile_;
bool use_multilogin_;
CoreAccountId account_id_; CoreAccountId account_id_;
base::OnceClosure callback_; base::OnceClosure callback_;
bool reconcile_error_encountered_ = false; bool reconcile_error_encountered_ = false;
...@@ -76,10 +106,13 @@ class DiceInterceptedSessionStartupHelper ...@@ -76,10 +106,13 @@ class DiceInterceptedSessionStartupHelper
accounts_in_cookie_observer_{this}; accounts_in_cookie_observer_{this};
base::ScopedObservation<AccountReconcilor, AccountReconcilor::Observer> base::ScopedObservation<AccountReconcilor, AccountReconcilor::Observer>
reconcilor_observer_{this}; reconcilor_observer_{this};
std::unique_ptr<AccountReconcilor::Lock> reconcilor_lock_;
base::TimeTicks session_startup_time_; base::TimeTicks session_startup_time_;
// Timeout while waiting for the account to be added to the cookies in the new // Timeout while waiting for the account to be added to the cookies in the new
// profile. // profile.
base::CancelableOnceCallback<void()> on_cookie_update_timeout_; base::CancelableOnceCallback<void()> on_cookie_update_timeout_;
base::WeakPtrFactory<DiceInterceptedSessionStartupHelper> weak_factory_{this};
}; };
#endif // CHROME_BROWSER_SIGNIN_DICE_INTERCEPTED_SESSION_STARTUP_HELPER_H_ #endif // CHROME_BROWSER_SIGNIN_DICE_INTERCEPTED_SESSION_STARTUP_HELPER_H_
...@@ -271,16 +271,16 @@ void DiceWebSigninInterceptor::CreateBrowserAfterSigninInterception( ...@@ -271,16 +271,16 @@ void DiceWebSigninInterceptor::CreateBrowserAfterSigninInterception(
CoreAccountId account_id, CoreAccountId account_id,
content::WebContents* intercepted_contents, content::WebContents* intercepted_contents,
std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> bubble_handle, std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> bubble_handle,
bool show_customization_bubble) { bool is_new_profile) {
DCHECK(!session_startup_helper_); DCHECK(!session_startup_helper_);
DCHECK(bubble_handle); DCHECK(bubble_handle);
interception_bubble_handle_ = std::move(bubble_handle); interception_bubble_handle_ = std::move(bubble_handle);
session_startup_helper_ = session_startup_helper_ =
std::make_unique<DiceInterceptedSessionStartupHelper>( std::make_unique<DiceInterceptedSessionStartupHelper>(
profile_, account_id, intercepted_contents); profile_, is_new_profile, account_id, intercepted_contents);
session_startup_helper_->Startup( session_startup_helper_->Startup(
base::BindOnce(&DiceWebSigninInterceptor::OnNewBrowserCreated, base::BindOnce(&DiceWebSigninInterceptor::OnNewBrowserCreated,
base::Unretained(this), show_customization_bubble)); base::Unretained(this), is_new_profile));
} }
void DiceWebSigninInterceptor::Shutdown() { void DiceWebSigninInterceptor::Shutdown() {
...@@ -477,21 +477,22 @@ void DiceWebSigninInterceptor::OnNewSignedInProfileCreated( ...@@ -477,21 +477,22 @@ void DiceWebSigninInterceptor::OnNewSignedInProfileCreated(
return; return;
} }
bool show_customization_bubble = false; // The profile color is defined only when the profile has just been created
if (profile_color.has_value()) { // (with interception type kMultiUser or kEnterprise). If the profile is not
// The profile color is defined only when the profile has just been created // new (kProfileSwitch) or if it is a guest profile, then the color is not
// (with interception type kMultiUser or kEnterprise). If the profile is not // updated.
// new (kProfileSwitch), then the color is not updated. bool is_new_profile = profile_color.has_value();
if (is_new_profile) {
base::UmaHistogramTimes( base::UmaHistogramTimes(
"Signin.Intercept.ProfileCreationDuration", "Signin.Intercept.ProfileCreationDuration",
base::TimeTicks::Now() - profile_creation_start_time_); base::TimeTicks::Now() - profile_creation_start_time_);
ProfileMetrics::LogProfileAddNewUser( ProfileMetrics::LogProfileAddNewUser(
ProfileMetrics::ADD_NEW_USER_SIGNIN_INTERCEPTION); ProfileMetrics::ADD_NEW_USER_SIGNIN_INTERCEPTION);
// Apply the new color to the profile. if (!new_profile->IsEphemeralGuestProfile()) {
ThemeServiceFactory::GetForProfile(new_profile) // Apply the new color to the profile.
->BuildAutogeneratedThemeFromColor(*profile_color); ThemeServiceFactory::GetForProfile(new_profile)
// Show the customization UI to allow changing the color. ->BuildAutogeneratedThemeFromColor(*profile_color);
show_customization_bubble = !new_profile->IsEphemeralGuestProfile(); }
} else { } else {
base::UmaHistogramTimes( base::UmaHistogramTimes(
"Signin.Intercept.ProfileSwitchDuration", "Signin.Intercept.ProfileSwitchDuration",
...@@ -503,16 +504,15 @@ void DiceWebSigninInterceptor::OnNewSignedInProfileCreated( ...@@ -503,16 +504,15 @@ void DiceWebSigninInterceptor::OnNewSignedInProfileCreated(
DiceWebSigninInterceptorFactory::GetForProfile(new_profile) DiceWebSigninInterceptorFactory::GetForProfile(new_profile)
->CreateBrowserAfterSigninInterception( ->CreateBrowserAfterSigninInterception(
account_id_, web_contents(), std::move(interception_bubble_handle_), account_id_, web_contents(), std::move(interception_bubble_handle_),
show_customization_bubble); is_new_profile);
Reset(); Reset();
} }
void DiceWebSigninInterceptor::OnNewBrowserCreated( void DiceWebSigninInterceptor::OnNewBrowserCreated(bool is_new_profile) {
bool show_customization_bubble) {
DCHECK(interception_bubble_handle_); DCHECK(interception_bubble_handle_);
interception_bubble_handle_.reset(); // Close the bubble now. interception_bubble_handle_.reset(); // Close the bubble now.
session_startup_helper_.reset(); session_startup_helper_.reset();
if (show_customization_bubble) { if (is_new_profile && !profile_->IsEphemeralGuestProfile()) {
Browser* browser = chrome::FindBrowserWithProfile(profile_); Browser* browser = chrome::FindBrowserWithProfile(profile_);
DCHECK(browser); DCHECK(browser);
delegate_->ShowProfileCustomizationBubble(browser); delegate_->ShowProfileCustomizationBubble(browser);
......
...@@ -205,14 +205,12 @@ class DiceWebSigninInterceptor : public KeyedService, ...@@ -205,14 +205,12 @@ class DiceWebSigninInterceptor : public KeyedService,
// `intercepted_contents` may be null if the tab was already closed. // `intercepted_contents` may be null if the tab was already closed.
// The intercepted web contents belong to the source profile (which is not the // The intercepted web contents belong to the source profile (which is not the
// profile attached to this service). // profile attached to this service).
// `show_customization_bubble` indicates whether the customization bubble
// should be shown after the browser is opened.
void CreateBrowserAfterSigninInterception( void CreateBrowserAfterSigninInterception(
CoreAccountId account_id, CoreAccountId account_id,
content::WebContents* intercepted_contents, content::WebContents* intercepted_contents,
std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle> std::unique_ptr<ScopedDiceWebSigninInterceptionBubbleHandle>
bubble_handle, bubble_handle,
bool show_customization_bubble); bool is_new_profile);
// Returns the outcome of the interception heuristic. // Returns the outcome of the interception heuristic.
// If the outcome is kInterceptProfileSwitch, the target profile is returned // If the outcome is kInterceptProfileSwitch, the target profile is returned
...@@ -283,7 +281,7 @@ class DiceWebSigninInterceptor : public KeyedService, ...@@ -283,7 +281,7 @@ class DiceWebSigninInterceptor : public KeyedService,
// Called when the new browser is created after interception. Passed as // Called when the new browser is created after interception. Passed as
// callback to `session_startup_helper_`. // callback to `session_startup_helper_`.
void OnNewBrowserCreated(bool show_customization_bubble); void OnNewBrowserCreated(bool is_new_profile);
// Returns a 8-bit hash of the email that can be persisted. // Returns a 8-bit hash of the email that can be persisted.
static std::string GetPersistentEmailHash(const std::string& email); static std::string GetPersistentEmailHash(const std::string& email);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/signin/dice_web_signin_interceptor.h" #include "chrome/browser/signin/dice_web_signin_interceptor.h"
#include <map> #include <map>
#include <string>
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/run_loop.h" #include "base/run_loop.h"
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
#include "chrome/browser/profiles/profile_window.h" #include "chrome/browser/profiles/profile_window.h"
#include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/chrome_signin_client_factory.h"
#include "chrome/browser/signin/chrome_signin_client_test_util.h" #include "chrome/browser/signin/chrome_signin_client_test_util.h"
#include "chrome/browser/signin/dice_intercepted_session_startup_helper.h"
#include "chrome/browser/signin/dice_web_signin_interceptor_factory.h" #include "chrome/browser/signin/dice_web_signin_interceptor_factory.h"
#include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
...@@ -38,11 +40,33 @@ ...@@ -38,11 +40,33 @@
#include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/signin/public/identity_manager/primary_account_mutator.h" #include "components/signin/public/identity_manager/primary_account_mutator.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
#include "google_apis/gaia/gaia_urls.h"
#include "services/network/test/test_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace { namespace {
// Fake response for OAuth multilogin.
const char kMultiloginSuccessResponse[] =
R"()]}'
{
"status": "OK",
"cookies":[
{
"name":"SID",
"value":"SID_value",
"domain":".google.fr",
"path":"/",
"isSecure":true,
"isHttpOnly":false,
"priority":"HIGH",
"maxAge":63070000
}
]
}
)";
class FakeDiceWebSigninInterceptorDelegate; class FakeDiceWebSigninInterceptorDelegate;
class FakeBubbleHandle : public ScopedDiceWebSigninInterceptionBubbleHandle, class FakeBubbleHandle : public ScopedDiceWebSigninInterceptionBubbleHandle,
...@@ -71,6 +95,7 @@ class FakeDiceWebSigninInterceptorDelegate ...@@ -71,6 +95,7 @@ class FakeDiceWebSigninInterceptorDelegate
SigninInterceptionResult::kAccepted)); SigninInterceptionResult::kAccepted));
return bubble_handle; return bubble_handle;
} }
void ShowProfileCustomizationBubble(Browser* browser) override { void ShowProfileCustomizationBubble(Browser* browser) override {
EXPECT_FALSE(customized_browser_) EXPECT_FALSE(customized_browser_)
<< "Customization must be shown only once."; << "Customization must be shown only once.";
...@@ -78,6 +103,7 @@ class FakeDiceWebSigninInterceptorDelegate ...@@ -78,6 +103,7 @@ class FakeDiceWebSigninInterceptorDelegate
} }
Browser* customized_browser() { return customized_browser_; } Browser* customized_browser() { return customized_browser_; }
void set_expected_interception_type( void set_expected_interception_type(
DiceWebSigninInterceptor::SigninInterceptionType type) { DiceWebSigninInterceptor::SigninInterceptionType type) {
expected_interception_type_ = type; expected_interception_type_ = type;
...@@ -157,8 +183,18 @@ void CheckHistograms(const base::HistogramTester& histogram_tester, ...@@ -157,8 +183,18 @@ void CheckHistograms(const base::HistogramTester& histogram_tester,
profile_creation_count); profile_creation_count);
histogram_tester.ExpectTotalCount("Signin.Intercept.ProfileSwitchDuration", histogram_tester.ExpectTotalCount("Signin.Intercept.ProfileSwitchDuration",
profile_switch_count); profile_switch_count);
histogram_tester.ExpectTotalCount("Signin.Intercept.SessionStartupDuration", histogram_tester.ExpectTotalCount(
1); "Signin.Intercept.SessionStartupDuration.Multilogin",
profile_creation_count);
histogram_tester.ExpectTotalCount(
"Signin.Intercept.SessionStartupDuration.Reconcilor",
profile_switch_count);
histogram_tester.ExpectUniqueSample(
"Signin.Intercept.SessionStartupResult",
profile_switch_count
? DiceInterceptedSessionStartupHelper::Result::kReconcilorSuccess
: DiceInterceptedSessionStartupHelper::Result::kMultiloginSuccess,
1);
} }
} // namespace } // namespace
...@@ -196,6 +232,7 @@ class DiceWebSigninInterceptorBrowserTest : public InProcessBrowserTest { ...@@ -196,6 +232,7 @@ class DiceWebSigninInterceptorBrowserTest : public InProcessBrowserTest {
} }
private: private:
// InProcessBrowserTest:
void SetUpOnMainThread() override { void SetUpOnMainThread() override {
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
identity_test_env_profile_adaptor_ = identity_test_env_profile_adaptor_ =
...@@ -267,12 +304,30 @@ IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, InterceptionTest) { ...@@ -267,12 +304,30 @@ IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, InterceptionTest) {
DCHECK(account_info.IsValid()); DCHECK(account_info.IsValid());
identity_test_env()->UpdateAccountInfoForAccount(account_info); identity_test_env()->UpdateAccountInfoForAccount(account_info);
// Instantly return from Gaia calls, to avoid timing out when injecting the
// account in the new profile.
network::TestURLLoaderFactory* loader_factory = test_url_loader_factory();
loader_factory->SetInterceptor(base::BindLambdaForTesting(
[loader_factory](const network::ResourceRequest& request) {
std::string path = request.url.path();
if (path == "/ListAccounts" || path == "/GetCheckConnectionInfo") {
loader_factory->AddResponse(request.url.spec(), std::string());
return;
}
if (path == "/oauth/multilogin") {
loader_factory->AddResponse(request.url.spec(),
kMultiloginSuccessResponse);
return;
}
}));
// Add a tab. // Add a tab.
GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse"); GURL intercepted_url = embedded_test_server()->GetURL("/defaultresponse");
content::WebContents* web_contents = AddTab(intercepted_url); content::WebContents* web_contents = AddTab(intercepted_url);
int original_tab_count = browser()->tab_strip_model()->count(); int original_tab_count = browser()->tab_strip_model()->count();
// Do the signin interception. // Do the signin interception.
EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
Profile* new_profile = Profile* new_profile =
InterceptAndWaitProfileCreation(web_contents, account_info.account_id); InterceptAndWaitProfileCreation(web_contents, account_info.account_id);
ASSERT_TRUE(new_profile); ASSERT_TRUE(new_profile);
...@@ -284,6 +339,9 @@ IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, InterceptionTest) { ...@@ -284,6 +339,9 @@ IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, InterceptionTest) {
EXPECT_TRUE(new_identity_manager->HasAccountWithRefreshToken( EXPECT_TRUE(new_identity_manager->HasAccountWithRefreshToken(
account_info.account_id)); account_info.account_id));
IdentityTestEnvironmentProfileAdaptor adaptor(new_profile);
adaptor.identity_test_env()->SetAutomaticIssueOfAccessTokens(true);
// Check the profile name. // Check the profile name.
ProfileAttributesEntry* entry = nullptr; ProfileAttributesEntry* entry = nullptr;
ProfileAttributesStorage& storage = ProfileAttributesStorage& storage =
...@@ -296,15 +354,10 @@ IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, InterceptionTest) { ...@@ -296,15 +354,10 @@ IN_PROC_BROWSER_TEST_F(DiceWebSigninInterceptorBrowserTest, InterceptionTest) {
EXPECT_TRUE(ThemeServiceFactory::GetForProfile(new_profile) EXPECT_TRUE(ThemeServiceFactory::GetForProfile(new_profile)
->UsingAutogeneratedTheme()); ->UsingAutogeneratedTheme());
// Add the account to the cookies (simulates the account reconcilor).
EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
signin::SetCookieAccounts(new_identity_manager, test_url_loader_factory(),
{{account_info.email, account_info.gaia}});
// A browser has been created for the new profile and the tab was moved there. // A browser has been created for the new profile and the tab was moved there.
ASSERT_EQ(BrowserList::GetInstance()->size(), 2u); Browser* added_browser = ui_test_utils::WaitForBrowserToOpen();
Browser* added_browser = BrowserList::GetInstance()->get(1);
ASSERT_TRUE(added_browser); ASSERT_TRUE(added_browser);
ASSERT_EQ(BrowserList::GetInstance()->size(), 2u);
EXPECT_EQ(added_browser->profile(), new_profile); EXPECT_EQ(added_browser->profile(), new_profile);
EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1); EXPECT_EQ(browser()->tab_strip_model()->count(), original_tab_count - 1);
EXPECT_EQ(added_browser->tab_strip_model()->GetActiveWebContents()->GetURL(), EXPECT_EQ(added_browser->tab_strip_model()->GetActiveWebContents()->GetURL(),
......
...@@ -68476,6 +68476,18 @@ https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf ...@@ -68476,6 +68476,18 @@ https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
<int value="3" label="Not displayed"/> <int value="3" label="Not displayed"/>
</enum> </enum>
<enum name="SigninInterceptSessionStartupResult">
<int value="0" label="Nothing to do (Reconcilor)"/>
<int value="1" label="Nothing to do (Multilogin)"/>
<int value="2" label="Success (reconcilor)"/>
<int value="3" label="Success (multilogin)"/>
<int value="4" label="Success (other)"/>
<int value="5" label="Timeout (multilogin)"/>
<int value="6" label="Timeout (reconcilor)"/>
<int value="7" label="Transient error (multilogin)"/>
<int value="8" label="Persistent error (multilogin)"/>
</enum>
<enum name="SigninInvalidGaiaCredentialsReason"> <enum name="SigninInvalidGaiaCredentialsReason">
<int value="0" label="Unknown"/> <int value="0" label="Unknown"/>
<int value="1" label="Credentials rejected by server"/> <int value="1" label="Credentials rejected by server"/>
...@@ -439,6 +439,10 @@ prefs when the profile is loaded. --> ...@@ -439,6 +439,10 @@ prefs when the profile is loaded. -->
<histogram name="Signin.Intercept.SessionStartupDuration" units="ms" <histogram name="Signin.Intercept.SessionStartupDuration" units="ms"
expires_after="2021-08-12"> expires_after="2021-08-12">
<obsolete>
Replaced in M89 by Signin.Intercept.SessionStartupDuration.Multilogin and
Signin.Intercept.SessionStartupDuration.Reconcilor.
</obsolete>
<owner>alexilin@chromium.org</owner> <owner>alexilin@chromium.org</owner>
<owner>droger@chromium.org</owner> <owner>droger@chromium.org</owner>
<summary> <summary>
...@@ -447,6 +451,20 @@ prefs when the profile is loaded. --> ...@@ -447,6 +451,20 @@ prefs when the profile is loaded. -->
</summary> </summary>
</histogram> </histogram>
<histogram name="Signin.Intercept.SessionStartupDuration.{Method}" units="ms"
expires_after="2021-08-12">
<owner>alexilin@chromium.org</owner>
<owner>droger@chromium.org</owner>
<summary>
Records the duration of session startup time after signin interception using
{Method}. This includes waiting for the account to be available on the web.
</summary>
<token key="Method">
<variant name="Multilogin"/>
<variant name="Reconcilor"/>
</token>
</histogram>
<histogram name="Signin.Intercept.SessionStartupReconcileError" <histogram name="Signin.Intercept.SessionStartupReconcileError"
enum="BooleanPresent" expires_after="2021-08-12"> enum="BooleanPresent" expires_after="2021-08-12">
<owner>alexilin@chromium.org</owner> <owner>alexilin@chromium.org</owner>
...@@ -458,6 +476,16 @@ prefs when the profile is loaded. --> ...@@ -458,6 +476,16 @@ prefs when the profile is loaded. -->
</summary> </summary>
</histogram> </histogram>
<histogram name="Signin.Intercept.SessionStartupResult"
enum="SigninInterceptSessionStartupResult" expires_after="2021-08-12">
<owner>alexilin@chromium.org</owner>
<owner>droger@chromium.org</owner>
<summary>
Records the result of session startup after signin interception, which adds
the account on the web.
</summary>
</histogram>
<histogram base="true" name="Signin.InterceptResult" <histogram base="true" name="Signin.InterceptResult"
enum="SigninInterceptResult" expires_after="2021-08-12"> enum="SigninInterceptResult" expires_after="2021-08-12">
<!-- Name completed by histogram_suffixes name="SigninInterceptType" --> <!-- Name completed by histogram_suffixes name="SigninInterceptType" -->
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment