summaryrefslogtreecommitdiff
path: root/chromium/components/signin
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:20:33 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:28:57 +0000
commitd17ea114e5ef69ad5d5d7413280a13e6428098aa (patch)
tree2c01a75df69f30d27b1432467cfe7c1467a498da /chromium/components/signin
parent8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (diff)
downloadqtwebengine-chromium-d17ea114e5ef69ad5d5d7413280a13e6428098aa.tar.gz
BASELINE: Update Chromium to 67.0.3396.47
Change-Id: Idcb1341782e417561a2473eeecc82642dafda5b7 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/components/signin')
-rw-r--r--chromium/components/signin/core/browser/BUILD.gn28
-rw-r--r--chromium/components/signin/core/browser/account_fetcher_service.cc22
-rw-r--r--chromium/components/signin/core/browser/account_fetcher_service.h21
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.cc74
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.h11
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_delegate.cc5
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_delegate.h17
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_unittest.cc247
-rw-r--r--chromium/components/signin/core/browser/android/BUILD.gn1
-rw-r--r--chromium/components/signin/core/browser/child_account_info_fetcher_android.h1
-rw-r--r--chromium/components/signin/core/browser/cookie_settings_util.cc36
-rw-r--r--chromium/components/signin/core/browser/cookie_settings_util.h24
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc22
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h2
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc19
-rw-r--r--chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc1
-rw-r--r--chromium/components/signin/core/browser/fake_profile_oauth2_token_service.cc20
-rw-r--r--chromium/components/signin/core/browser/fake_profile_oauth2_token_service.h4
-rw-r--r--chromium/components/signin/core/browser/fake_signin_manager.cc17
-rw-r--r--chromium/components/signin/core/browser/fake_signin_manager.h2
-rw-r--r--chromium/components/signin/core/browser/profile_management_switches.cc13
-rw-r--r--chromium/components/signin/core/browser/profile_management_switches.h3
-rw-r--r--chromium/components/signin/core/browser/profile_management_switches_unittest.cc2
-rw-r--r--chromium/components/signin/core/browser/scoped_account_consistency.cc2
-rw-r--r--chromium/components/signin/core/browser/signin_error_controller.cc2
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.cc12
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper.h5
-rw-r--r--chromium/components/signin/core/browser/signin_header_helper_unittest.cc2
-rw-r--r--chromium/components/signin/core/browser/signin_manager.cc40
-rw-r--r--chromium/components/signin/core/browser/signin_manager.h19
-rw-r--r--chromium/components/signin/core/browser/signin_manager_unittest.cc79
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.cc559
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.h20
-rw-r--r--chromium/components/signin/core/browser/signin_metrics_unittest.cc190
-rw-r--r--chromium/components/signin/core/browser/signin_switches.h2
-rw-r--r--chromium/components/signin/core/browser/test_signin_client.cc20
-rw-r--r--chromium/components/signin/core/browser/test_signin_client.h11
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h3
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm26
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm31
40 files changed, 1316 insertions, 299 deletions
diff --git a/chromium/components/signin/core/browser/BUILD.gn b/chromium/components/signin/core/browser/BUILD.gn
index cf446098cc5..9f7fb37b111 100644
--- a/chromium/components/signin/core/browser/BUILD.gn
+++ b/chromium/components/signin/core/browser/BUILD.gn
@@ -9,8 +9,8 @@ if (is_android) {
import("//build/config/android/rules.gni")
}
-buildflag_header("signin_features") {
- header = "signin_features.h"
+buildflag_header("signin_buildflags") {
+ header = "signin_buildflags.h"
flags = [
"ENABLE_DICE_SUPPORT=$enable_dice_support",
"ENABLE_MIRROR=$enable_mirror",
@@ -28,6 +28,20 @@ static_library("account_info") {
]
}
+# Split into its own target to allow browser clients of the Identity Service to
+# record browser-specific signin metrics without having to depend on all of
+# //components/signin/core/browser.
+static_library("signin_metrics") {
+ sources = [
+ "signin_metrics.cc",
+ "signin_metrics.h",
+ ]
+ public_deps = [
+ "//base",
+ "//google_apis",
+ ]
+}
+
static_library("browser") {
sources = [
"about_signin_internals.cc",
@@ -54,6 +68,8 @@ static_library("browser") {
"child_account_info_fetcher_impl.h",
"chrome_connected_header_helper.cc",
"chrome_connected_header_helper.h",
+ "cookie_settings_util.cc",
+ "cookie_settings_util.h",
"dice_account_reconcilor_delegate.cc",
"dice_account_reconcilor_delegate.h",
"dice_header_helper.cc",
@@ -84,8 +100,6 @@ static_library("browser") {
"signin_manager.h",
"signin_manager_base.cc",
"signin_manager_base.h",
- "signin_metrics.cc",
- "signin_metrics.h",
"signin_pref_names.cc",
"signin_pref_names.h",
"signin_status_metrics_provider.cc",
@@ -108,6 +122,8 @@ static_library("browser") {
public_deps = [
":account_info",
+ ":signin_buildflags",
+ ":signin_metrics",
"//base",
"//components/content_settings/core/browser",
"//components/content_settings/core/common",
@@ -115,7 +131,6 @@ static_library("browser") {
"//components/keyed_service/core",
"//components/prefs",
"//components/signin/core/account_id",
- "//components/signin/core/browser:signin_features",
"//google_apis",
"//net",
"//ui/gfx",
@@ -214,18 +229,19 @@ source_set("unit_tests") {
"signin_header_helper_unittest.cc",
"signin_investigator_unittest.cc",
"signin_manager_unittest.cc",
+ "signin_metrics_unittest.cc",
"signin_status_metrics_provider_unittest.cc",
"webdata/token_service_table_unittest.cc",
]
deps = [
+ ":signin_buildflags",
":test_support",
"//base/test:test_support",
"//components/content_settings/core/browser",
"//components/os_crypt:test_support",
"//components/pref_registry:pref_registry",
"//components/prefs",
- "//components/signin/core/browser:signin_features",
"//components/sync_preferences",
"//components/sync_preferences:test_support",
"//testing/gmock",
diff --git a/chromium/components/signin/core/browser/account_fetcher_service.cc b/chromium/components/signin/core/browser/account_fetcher_service.cc
index 7027fef0164..255c520d0ec 100644
--- a/chromium/components/signin/core/browser/account_fetcher_service.cc
+++ b/chromium/components/signin/core/browser/account_fetcher_service.cc
@@ -188,7 +188,7 @@ void AccountFetcherService::ScheduleNextRefresh() {
DCHECK(network_fetches_enabled_);
const base::TimeDelta time_since_update = base::Time::Now() - last_updated_;
- if(time_since_update > kRefreshFromTokenServiceDelay) {
+ if (time_since_update > kRefreshFromTokenServiceDelay) {
RefreshAllAccountsAndScheduleNext();
} else {
timer_.Start(FROM_HERE, kRefreshFromTokenServiceDelay - time_since_update,
@@ -267,7 +267,6 @@ AccountFetcherService::GetOrCreateImageFetcher() {
if (!image_fetcher_) {
image_fetcher_ = std::make_unique<image_fetcher::ImageFetcherImpl>(
std::move(image_decoder_), signin_client_->GetURLRequestContext());
- image_fetcher_->SetImageFetcherDelegate(this);
}
return image_fetcher_.get();
}
@@ -305,9 +304,10 @@ void AccountFetcherService::FetchAccountImage(const std::string& account_id) {
})");
GURL image_url_with_size(signin::GetAvatarImageURLWithOptions(
picture_url, kAccountImageDownloadSize, true /* no_silhouette */));
- GetOrCreateImageFetcher()->StartOrQueueNetworkRequest(
- account_id, image_url_with_size,
- image_fetcher::ImageFetcher::ImageFetcherCallback(), traffic_annotation);
+ auto callback = base::BindRepeating(&AccountFetcherService::OnImageFetched,
+ base::Unretained(this));
+ GetOrCreateImageFetcher()->FetchImage(account_id, image_url_with_size,
+ callback, traffic_annotation);
}
void AccountFetcherService::SetIsChildAccount(const std::string& account_id,
@@ -326,8 +326,7 @@ void AccountFetcherService::OnUserInfoFetchFailure(
void AccountFetcherService::OnRefreshTokenAvailable(
const std::string& account_id) {
TRACE_EVENT1("AccountFetcherService",
- "AccountFetcherService::OnRefreshTokenAvailable",
- "account_id",
+ "AccountFetcherService::OnRefreshTokenAvailable", "account_id",
account_id);
DVLOG(1) << "AVAILABLE " << account_id;
@@ -347,8 +346,7 @@ void AccountFetcherService::OnRefreshTokenAvailable(
void AccountFetcherService::OnRefreshTokenRevoked(
const std::string& account_id) {
TRACE_EVENT1("AccountFetcherService",
- "AccountFetcherService::OnRefreshTokenRevoked",
- "account_id",
+ "AccountFetcherService::OnRefreshTokenRevoked", "account_id",
account_id);
DVLOG(1) << "REVOKED " << account_id;
@@ -367,7 +365,9 @@ void AccountFetcherService::OnRefreshTokensLoaded() {
MaybeEnableNetworkFetches();
}
-void AccountFetcherService::OnImageFetched(const std::string& id,
- const gfx::Image& image) {
+void AccountFetcherService::OnImageFetched(
+ const std::string& id,
+ const gfx::Image& image,
+ const image_fetcher::RequestMetadata&) {
account_tracker_service_->SetAccountImage(id, image);
}
diff --git a/chromium/components/signin/core/browser/account_fetcher_service.h b/chromium/components/signin/core/browser/account_fetcher_service.h
index 6e864355521..993fa675821 100644
--- a/chromium/components/signin/core/browser/account_fetcher_service.h
+++ b/chromium/components/signin/core/browser/account_fetcher_service.h
@@ -13,9 +13,9 @@
#include "base/macros.h"
#include "base/sequence_checker.h"
#include "base/timer/timer.h"
-#include "components/image_fetcher/core/image_fetcher_delegate.h"
#include "components/keyed_service/core/keyed_service.h"
#include "google_apis/gaia/oauth2_token_service.h"
+#include "ui/gfx/image/image.h"
class AccountInfoFetcher;
class AccountTrackerService;
@@ -23,7 +23,12 @@ class ChildAccountInfoFetcher;
class OAuth2TokenService;
class SigninClient;
+namespace base {
+class DictionaryValue;
+}
+
namespace image_fetcher {
+struct RequestMetadata;
class ImageDecoder;
class ImageFetcherImpl;
} // namespace image_fetcher
@@ -40,8 +45,7 @@ class PrefRegistrySyncable;
// to child account info fetching.
class AccountFetcherService : public KeyedService,
- public OAuth2TokenService::Observer,
- public image_fetcher::ImageFetcherDelegate {
+ public OAuth2TokenService::Observer {
public:
// Name of the preference that tracks the int64_t representation of the last
// time the AccountTrackerService was updated.
@@ -125,12 +129,13 @@ class AccountFetcherService : public KeyedService,
// Called in |OnUserInfoFetchSuccess| after the account info has been fetched.
void FetchAccountImage(const std::string& account_id);
- // image_fetcher::ImageFetcherDelegate:
- void OnImageFetched(const std::string& id, const gfx::Image& image) override;
+ void OnImageFetched(const std::string& id,
+ const gfx::Image& image,
+ const image_fetcher::RequestMetadata& image_metadata);
- AccountTrackerService* account_tracker_service_; // Not owned.
- OAuth2TokenService* token_service_; // Not owned.
- SigninClient* signin_client_; // Not owned.
+ AccountTrackerService* account_tracker_service_; // Not owned.
+ OAuth2TokenService* token_service_; // Not owned.
+ SigninClient* signin_client_; // Not owned.
invalidation::InvalidationService* invalidation_service_; // Not owned.
bool network_fetches_enabled_;
bool profile_loaded_;
diff --git a/chromium/components/signin/core/browser/account_reconcilor.cc b/chromium/components/signin/core/browser/account_reconcilor.cc
index 3b2304f9233..46f6ae05c21 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor.cc
@@ -20,13 +20,15 @@
#include "components/signin/core/browser/account_reconcilor_delegate.h"
#include "components/signin/core/browser/profile_management_switches.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/signin_buildflags.h"
#include "components/signin/core/browser/signin_client.h"
-#include "components/signin/core/browser/signin_features.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
+using signin::AccountReconcilorDelegate;
+
namespace {
// String used for source parameter in GAIA cookie manager calls.
@@ -260,6 +262,20 @@ void AccountReconcilor::OnRefreshTokensLoaded() {
StartReconcile();
}
+void AccountReconcilor::OnAuthErrorChanged(
+ const std::string& account_id,
+ const GoogleServiceAuthError& error) {
+ // Gaia cookies may be invalidated server-side and the client does not get any
+ // notification when this happens.
+ // Gaia cookies derived from refresh tokens are always invalidated server-side
+ // when the tokens are revoked. Trigger a ListAccounts to Gaia when this
+ // happens to make sure that the cookies accounts are up-to-date.
+ // This should cover well the Mirror and Desktop Identity Consistency cases as
+ // the cookies are always bound to the refresh tokens in these cases.
+ if (error != GoogleServiceAuthError::AuthErrorNone())
+ cookie_manager_service_->TriggerListAccounts(kSource);
+}
+
void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
reconcile_is_noop_ = false;
if (!delegate_->IsAccountConsistencyEnforced()) {
@@ -312,11 +328,10 @@ void AccountReconcilor::StartReconcile() {
base::Unretained(this)));
}
- primary_account_ = signin_manager_->GetAuthenticatedAccountId();
- if (token_service_->GetDelegate()->RefreshTokenHasError(primary_account_) &&
+ if (token_service_->RefreshTokenHasError(
+ signin_manager_->GetAuthenticatedAccountId()) &&
delegate_->ShouldAbortReconcileIfPrimaryHasError()) {
VLOG(1) << "AccountReconcilor::StartReconcile: primary has error, abort.";
- primary_account_.clear();
return;
}
@@ -353,29 +368,48 @@ void AccountReconcilor::OnGaiaAccountsInCookieUpdated(
return;
}
+ std::string primary_account = signin_manager_->GetAuthenticatedAccountId();
std::vector<gaia::ListedAccount> verified_gaia_accounts =
FilterUnverifiedAccounts(accounts);
VLOG_IF(1, verified_gaia_accounts.size() < accounts.size())
- << "Ignoring " << accounts.size() - verified_gaia_accounts.size()
+ << "Ignore " << accounts.size() - verified_gaia_accounts.size()
<< " unverified account(s).";
- if (delegate_->ShouldRevokeAllSecondaryTokensBeforeReconcile(
- verified_gaia_accounts)) {
- for (const std::string& account : token_service_->GetAccounts()) {
- if (account != primary_account_)
+ // Revoking tokens for secondary accounts causes the AccountTracker to
+ // completely remove them from Chrome.
+ // Revoking the token for the primary account is not supported (it should be
+ // signed out or put to auth error state instead).
+ AccountReconcilorDelegate::RevokeTokenOption revoke_option =
+ delegate_->ShouldRevokeSecondaryTokensBeforeReconcile(
+ verified_gaia_accounts);
+ for (const std::string& account : token_service_->GetAccounts()) {
+ if (account == primary_account)
+ continue;
+ switch (revoke_option) {
+ case AccountReconcilorDelegate::RevokeTokenOption::kRevokeIfInError:
+ if (token_service_->RefreshTokenHasError(account)) {
+ VLOG(1) << "Revoke token for " << account;
+ token_service_->RevokeCredentials(account);
+ }
+ break;
+ case AccountReconcilorDelegate::RevokeTokenOption::kRevoke:
+ VLOG(1) << "Revoke token for " << account;
token_service_->RevokeCredentials(account);
+ break;
+ case AccountReconcilorDelegate::RevokeTokenOption::kDoNotRevoke:
+ // Do nothing.
+ break;
}
}
if (delegate_->ShouldAbortReconcileIfPrimaryHasError() &&
- token_service_->GetDelegate()->RefreshTokenHasError(primary_account_)) {
+ token_service_->RefreshTokenHasError(primary_account)) {
VLOG(1) << "Primary account has error, abort.";
- primary_account_.clear();
is_reconcile_started_ = false;
return;
}
- FinishReconcile(LoadValidAccountsFromTokenService(),
+ FinishReconcile(primary_account, LoadValidAccountsFromTokenService(),
std::move(verified_gaia_accounts));
} else {
if (is_reconcile_started_)
@@ -392,9 +426,9 @@ std::vector<std::string> AccountReconcilor::LoadValidAccountsFromTokenService()
// reconcile them, since it won't work anyway. If the list ends up being
// empty then don't reconcile any accounts.
for (auto i = chrome_accounts.begin(); i != chrome_accounts.end(); ++i) {
- if (token_service_->GetDelegate()->RefreshTokenHasError(*i)) {
+ if (token_service_->RefreshTokenHasError(*i)) {
VLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: " << *i
- << " has error, won't reconcile";
+ << " has error, don't reconcile";
i->clear();
}
}
@@ -417,13 +451,14 @@ void AccountReconcilor::OnReceivedManageAccountsResponse(
}
void AccountReconcilor::FinishReconcile(
+ const std::string& primary_account,
const std::vector<std::string>& chrome_accounts,
std::vector<gaia::ListedAccount>&& gaia_accounts) {
VLOG(1) << "AccountReconcilor::FinishReconcile";
DCHECK(add_to_cookie_.empty());
std::string first_account = delegate_->GetFirstGaiaAccountForReconcile(
- chrome_accounts, gaia_accounts, primary_account_, first_execution_);
+ chrome_accounts, gaia_accounts, primary_account, first_execution_);
// |first_account| must be in |chrome_accounts|.
DCHECK(first_account.empty() ||
(std::find(chrome_accounts.begin(), chrome_accounts.end(),
@@ -461,7 +496,7 @@ void AccountReconcilor::FinishReconcile(
// Gaia cookie has been cleared or was already empty.
DCHECK((first_account_mismatch && rebuild_cookie) ||
(number_gaia_accounts == 0));
- RevokeAllSecondaryTokens(chrome_accounts);
+ RevokeAllSecondaryTokens(primary_account, chrome_accounts);
} else {
// Create a list of accounts that need to be added to the Gaia cookie.
add_to_cookie_.push_back(first_account);
@@ -506,7 +541,7 @@ void AccountReconcilor::FinishReconcile(
}
void AccountReconcilor::AbortReconcile() {
- VLOG(1) << "AccountReconcilor::AbortReconcile: we'll try again later";
+ VLOG(1) << "AccountReconcilor::AbortReconcile: try again later";
add_to_cookie_.clear();
CalculateIfReconcileIsDone();
}
@@ -540,12 +575,13 @@ void AccountReconcilor::ScheduleStartReconcileIfChromeAccountsChanged() {
}
void AccountReconcilor::RevokeAllSecondaryTokens(
+ const std::string& primary_account,
const std::vector<std::string>& chrome_accounts) {
for (const std::string& account : chrome_accounts) {
- if (account != primary_account_) {
+ if (account != primary_account) {
reconcile_is_noop_ = false;
if (delegate_->IsAccountConsistencyEnforced()) {
- VLOG(1) << "Revoking token for " << account;
+ VLOG(1) << "Revoke token for " << account;
token_service_->RevokeCredentials(account);
}
}
diff --git a/chromium/components/signin/core/browser/account_reconcilor.h b/chromium/components/signin/core/browser/account_reconcilor.h
index db4adb51b2a..7aaed2aec30 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.h
+++ b/chromium/components/signin/core/browser/account_reconcilor.h
@@ -121,6 +121,7 @@ class AccountReconcilor : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceLastKnownFirstAccount);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, UnverifiedAccountNoop);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, UnverifiedAccountMerge);
+ FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, HandleSigninDuringReconcile);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceMigrationAfterNoop);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
DiceNoMigrationWhenTokensNotReady);
@@ -148,6 +149,7 @@ class AccountReconcilor : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopWithDots);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopMultiple);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileAddToCookie);
+ FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, AuthErrorTriggersListAccount);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
SignoutAfterErrorDoesNotRecordUma);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
@@ -192,13 +194,15 @@ class AccountReconcilor : public KeyedService,
// Used during periodic reconciliation.
void StartReconcile();
// |gaia_accounts| are the accounts in the Gaia cookie.
- void FinishReconcile(const std::vector<std::string>& chrome_accounts,
+ void FinishReconcile(const std::string& primary_account,
+ const std::vector<std::string>& chrome_accounts,
std::vector<gaia::ListedAccount>&& gaia_accounts);
void AbortReconcile();
void CalculateIfReconcileIsDone();
void ScheduleStartReconcileIfChromeAccountsChanged();
- // Revokes tokens for all accounts in chrome_accounts but primary_account_.
+ // Revokes tokens for all accounts in chrome_accounts but the primary account.
void RevokeAllSecondaryTokens(
+ const std::string& primary_account,
const std::vector<std::string>& chrome_accounts);
// Returns the list of valid accounts from the TokenService.
@@ -229,6 +233,8 @@ class AccountReconcilor : public KeyedService,
// Overriden from OAuth2TokenService::Observer.
void OnEndBatchChanges() override;
void OnRefreshTokensLoaded() override;
+ void OnAuthErrorChanged(const std::string& account_id,
+ const GoogleServiceAuthError& error) override;
// Lock related methods.
void IncrementLockCount();
@@ -274,7 +280,6 @@ class AccountReconcilor : public KeyedService,
// Used during reconcile action.
// These members are used to validate the tokens in OAuth2TokenService.
- std::string primary_account_;
std::vector<std::string> add_to_cookie_;
bool chrome_accounts_changed_;
diff --git a/chromium/components/signin/core/browser/account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/account_reconcilor_delegate.cc
index fceec4c55d5..00ac6dde298 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_delegate.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor_delegate.cc
@@ -29,9 +29,10 @@ std::string AccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
return std::string();
}
-bool AccountReconcilorDelegate::ShouldRevokeAllSecondaryTokensBeforeReconcile(
+AccountReconcilorDelegate::RevokeTokenOption
+AccountReconcilorDelegate::ShouldRevokeSecondaryTokensBeforeReconcile(
const std::vector<gaia::ListedAccount>& gaia_accounts) {
- return false;
+ return RevokeTokenOption::kDoNotRevoke;
}
base::TimeDelta AccountReconcilorDelegate::GetReconcileTimeout() const {
diff --git a/chromium/components/signin/core/browser/account_reconcilor_delegate.h b/chromium/components/signin/core/browser/account_reconcilor_delegate.h
index 8960987632a..03553a98cee 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/account_reconcilor_delegate.h
@@ -19,6 +19,17 @@ namespace signin {
// Base class for AccountReconcilorDelegate.
class AccountReconcilorDelegate {
public:
+ // Options for revoking refresh tokens.
+ enum class RevokeTokenOption {
+ // Do not revoke the token.
+ kDoNotRevoke,
+ // Revoke the token if it is in auth error state.
+ kRevokeIfInError,
+ // Revoke the token.
+ // TODO(droger): remove this when Dice is launched.
+ kRevoke
+ };
+
virtual ~AccountReconcilorDelegate() {}
// Returns true if the reconcilor should reconcile the profile. Defaults to
@@ -43,9 +54,9 @@ class AccountReconcilorDelegate {
const std::string& primary_account,
bool first_execution) const;
- // Returns true if all secondary accounts should be cleared at the beginning
- // of the reconcile.
- virtual bool ShouldRevokeAllSecondaryTokensBeforeReconcile(
+ // Returns whether secondary accounts should be cleared at the beginning of
+ // the reconcile.
+ virtual RevokeTokenOption ShouldRevokeSecondaryTokensBeforeReconcile(
const std::vector<gaia::ListedAccount>& gaia_accounts);
// Called when reconcile is finished.
diff --git a/chromium/components/signin/core/browser/account_reconcilor_unittest.cc b/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
index abbd9b6df6a..de00a76dc77 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -26,14 +26,13 @@
#include "components/signin/core/browser/mirror_account_reconcilor_delegate.h"
#include "components/signin/core/browser/profile_management_switches.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
-#include "components/signin/core/browser/signin_features.h"
+#include "components/signin/core/browser/signin_buildflags.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "components/signin/core/browser/signin_pref_names.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -228,10 +227,6 @@ class AccountReconcilorTest : public ::testing::Test {
FakeSigninManagerForTesting* signin_manager() { return &signin_manager_; }
FakeProfileOAuth2TokenService* token_service() { return &token_service_; }
- FakeOAuth2TokenServiceDelegate* token_service_delegate() {
- return static_cast<FakeOAuth2TokenServiceDelegate*>(
- token_service_.GetDelegate());
- }
DiceTestSigninClient* test_signin_client() { return &test_signin_client_; }
AccountTrackerService* account_tracker() { return &account_tracker_; }
FakeGaiaCookieManagerService* cookie_manager_service() {
@@ -499,17 +494,17 @@ const AccountReconcilorTestDiceParam kDiceParams[] = {
{ "*xAB", "B", true, "", "*xAB", "B"},
{ "*xAB", "", true, "B", "*xAB", "B"},
// Sync enabled, token error on secondary.
- { "*AxB", "AB", true, "XA", "*AxB", "A"},
- { "*AxB", "BA", true, "XA", "*AxB", "A"},
- { "*AxB", "A", true, "", "*AxB", "A"},
- { "*AxB", "B", true, "XA", "*AxB", "A"},
- { "*AxB", "", true, "A", "*AxB", "A"},
+ { "*AxB", "AB", true, "XA", "*A", "A"},
+ { "*AxB", "BA", true, "XA", "*A", "A"},
+ { "*AxB", "A", true, "", "*A", "A"},
+ { "*AxB", "B", true, "XA", "*A", "A"},
+ { "*AxB", "", true, "A", "*A", "A"},
// Sync enabled, token error on both accounts.
- { "*xAxB", "AB", true, "X", "*xAxB", ""},
- { "*xAxB", "BA", true, "X", "*xAxB", ""},
- { "*xAxB", "A", true, "X", "*xAxB", ""},
- { "*xAxB", "B", true, "X", "*xAxB", ""},
- { "*xAxB", "", true, "", "*xAxB", ""},
+ { "*xAxB", "AB", true, "X", "*xA", ""},
+ { "*xAxB", "BA", true, "X", "*xA", ""},
+ { "*xAxB", "A", true, "X", "*xA", ""},
+ { "*xAxB", "B", true, "X", "*xA", ""},
+ { "*xAxB", "", true, "", "*xA", ""},
// Sync disabled.
{ "AB", "AB", true, "", "AB", "AB"},
{ "AB", "BA", true, "", "AB", "BA"},
@@ -517,23 +512,23 @@ const AccountReconcilorTestDiceParam kDiceParams[] = {
{ "AB", "B", true, "A", "AB", "BA"},
{ "AB", "", true, "AB", "AB", "AB"},
// Sync disabled, token error on first account.
- { "xAB", "AB", true, "XB", "xAB", "B"},
- { "xAB", "BA", true, "XB", "xAB", "B"},
- { "xAB", "A", true, "XB", "xAB", "B"},
- { "xAB", "B", true, "", "xAB", "B"},
- { "xAB", "", true, "B", "xAB", "B"},
+ { "xAB", "AB", true, "XB", "B", "B"},
+ { "xAB", "BA", true, "XB", "B", "B"},
+ { "xAB", "A", true, "XB", "B", "B"},
+ { "xAB", "B", true, "", "B", "B"},
+ { "xAB", "", true, "B", "B", "B"},
// Sync disabled, token error on second account .
- { "AxB", "AB", true, "XA", "AxB", "A"},
- { "AxB", "BA", true, "XA", "AxB", "A"},
- { "AxB", "A", true, "", "AxB", "A"},
- { "AxB", "B", true, "XA", "AxB", "A"},
- { "AxB", "", true, "A", "AxB", "A"},
+ { "AxB", "AB", true, "XA", "A", "A"},
+ { "AxB", "BA", true, "XA", "A", "A"},
+ { "AxB", "A", true, "", "A", "A"},
+ { "AxB", "B", true, "XA", "A", "A"},
+ { "AxB", "", true, "A", "A", "A"},
// Sync disabled, token error on both accounts.
- { "xAxB", "AB", true, "X", "xAxB", ""},
- { "xAxB", "BA", true, "X", "xAxB", ""},
- { "xAxB", "A", true, "X", "xAxB", ""},
- { "xAxB", "B", true, "X", "xAxB", ""},
- { "xAxB", "", true, "", "xAxB", ""},
+ { "xAxB", "AB", true, "X", "", ""},
+ { "xAxB", "BA", true, "X", "", ""},
+ { "xAxB", "A", true, "X", "", ""},
+ { "xAxB", "B", true, "X", "", ""},
+ { "xAxB", "", true, "", "", ""},
// Chrome is running: Do not change the order of accounts already present in
// the Gaia cookies.
@@ -550,17 +545,17 @@ const AccountReconcilorTestDiceParam kDiceParams[] = {
{ "*xAB", "B", false, "", "*xAB", "B"},
{ "*xAB", "", false, "B", "*xAB", "B"},
// Sync enabled, token error on secondary.
- { "*AxB", "AB", false, "XA", "*AxB", "A"},
- { "*AxB", "BA", false, "XA", "*AxB", "A"},
- { "*AxB", "A", false, "", "*AxB", "A"},
- { "*AxB", "B", false, "XA", "*AxB", "A"},
- { "*AxB", "", false, "A", "*AxB", "A"},
+ { "*AxB", "AB", false, "XA", "*A", "A"},
+ { "*AxB", "BA", false, "XA", "*A", "A"},
+ { "*AxB", "A", false, "", "*A", "A"},
+ { "*AxB", "B", false, "XA", "*A", "A"},
+ { "*AxB", "", false, "A", "*A", "A"},
// Sync enabled, token error on both accounts.
- { "*xAxB", "AB", false, "X", "*xAxB", ""},
- { "*xAxB", "BA", false, "X", "*xAxB", ""},
- { "*xAxB", "A", false, "X", "*xAxB", ""},
- { "*xAxB", "B", false, "X", "*xAxB", ""},
- { "*xAxB", "", false, "", "*xAxB", ""},
+ { "*xAxB", "AB", false, "X", "*xA", ""},
+ { "*xAxB", "BA", false, "X", "*xA", ""},
+ { "*xAxB", "A", false, "X", "*xA", ""},
+ { "*xAxB", "B", false, "X", "*xA", ""},
+ { "*xAxB", "", false, "", "*xA", ""},
// Sync disabled.
{ "AB", "AB", false, "", "AB", "AB"},
{ "AB", "BA", false, "", "AB", "BA"},
@@ -568,23 +563,23 @@ const AccountReconcilorTestDiceParam kDiceParams[] = {
{ "AB", "B", false, "A", "AB", "BA"},
{ "AB", "", false, "AB", "AB", "AB"},
// Sync disabled, token error on first account.
- { "xAB", "AB", false, "X", "xA", ""},
- { "xAB", "BA", false, "XB", "xAB", "B"},
- { "xAB", "A", false, "X", "xA", ""},
- { "xAB", "B", false, "", "xAB", "B"},
- { "xAB", "", false, "B", "xAB", "B"},
+ { "xAB", "AB", false, "X", "", ""},
+ { "xAB", "BA", false, "XB", "B", "B"},
+ { "xAB", "A", false, "X", "", ""},
+ { "xAB", "B", false, "", "B", "B"},
+ { "xAB", "", false, "B", "B", "B"},
// Sync disabled, token error on second account.
- { "AxB", "AB", false, "XA", "AxB", "A"},
- { "AxB", "BA", false, "X", "xB", ""},
- { "AxB", "A", false, "", "AxB", "A"},
- { "AxB", "B", false, "X", "xB", ""},
- { "AxB", "", false, "A", "AxB", "A"},
+ { "AxB", "AB", false, "XA", "A", "A"},
+ { "AxB", "BA", false, "X", "", ""},
+ { "AxB", "A", false, "", "A", "A"},
+ { "AxB", "B", false, "X", "", ""},
+ { "AxB", "", false, "A", "A", "A"},
// Sync disabled, token error on both accounts.
- { "xAxB", "AB", false, "X", "xAxB", ""},
- { "xAxB", "BA", false, "X", "xAxB", ""},
- { "xAxB", "A", false, "X", "xAxB", ""},
- { "xAxB", "B", false, "X", "xAxB", ""},
- { "xAxB", "", false, "", "xAxB", ""},
+ { "xAxB", "AB", false, "X", "", ""},
+ { "xAxB", "BA", false, "X", "", ""},
+ { "xAxB", "A", false, "X", "", ""},
+ { "xAxB", "B", false, "X", "", ""},
+ { "xAxB", "", false, "", "", ""},
// Miscellaneous cases.
// Check that unknown Gaia accounts are signed out.
@@ -598,8 +593,8 @@ const AccountReconcilorTestDiceParam kDiceParams[] = {
// Required for idempotency check.
{ "", "", false, "", "", ""},
{ "*A", "A", false, "", "*A", "A"},
- { "xB", "", false, "", "xB", ""},
- { "xA", "", false, "", "xA", ""},
+ { "A", "A", false, "", "A", "A"},
+ { "B", "B", false, "", "B", "B"},
{ "*xA", "", false, "", "*xA", ""},
{ "*xAB", "B", false, "", "*xAB", "B"},
};
@@ -660,9 +655,8 @@ class AccountReconcilorTestDice
std::string account_id =
PickAccountIdForAccount(token.gaia_id, token.email);
EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id));
- EXPECT_EQ(
- token.has_error,
- token_service()->GetDelegate()->RefreshTokenHasError(account_id));
+ EXPECT_EQ(token.has_error,
+ token_service()->RefreshTokenHasError(account_id));
if (token.is_authenticated) {
EXPECT_EQ(account_id, signin_manager()->GetAuthenticatedAccountId());
authenticated_account_found = true;
@@ -691,6 +685,24 @@ class AccountReconcilorTestDice
ADD_FAILURE() << "Could not check that reconcile is idempotent.";
}
+ void ConfigureCookieManagerService(const std::string& cookies) {
+ if (cookies.size() == 0) {
+ cookie_manager_service()->SetListAccountsResponseNoAccounts();
+ } else if (cookies.size() == 1) {
+ cookie_manager_service()->SetListAccountsResponseOneAccount(
+ accounts_[cookies[0]].email.c_str(),
+ accounts_[cookies[0]].gaia_id.c_str());
+ } else {
+ ASSERT_EQ(2u, cookies.size());
+ cookie_manager_service()->SetListAccountsResponseTwoAccounts(
+ accounts_[cookies[0]].email.c_str(),
+ accounts_[cookies[0]].gaia_id.c_str(),
+ accounts_[cookies[1]].email.c_str(),
+ accounts_[cookies[1]].gaia_id.c_str());
+ }
+ cookie_manager_service()->set_list_accounts_stale_for_testing(true);
+ }
+
std::map<char, Account> accounts_;
};
@@ -714,7 +726,7 @@ TEST_P(AccountReconcilorTestDice, TableRowTest) {
else
token_service()->UpdateCredentials(account_id, "refresh_token");
if (token.has_error) {
- token_service_delegate()->SetLastErrorForAccount(
+ token_service()->UpdateAuthErrorForTesting(
account_id, GoogleServiceAuthError(
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
}
@@ -723,20 +735,7 @@ TEST_P(AccountReconcilorTestDice, TableRowTest) {
// Setup cookies.
std::string cookies(GetParam().cookies);
- if (cookies.size() == 0) {
- cookie_manager_service()->SetListAccountsResponseNoAccounts();
- } else if (cookies.size() == 1) {
- cookie_manager_service()->SetListAccountsResponseOneAccount(
- accounts_[GetParam().cookies[0]].email.c_str(),
- accounts_[GetParam().cookies[0]].gaia_id.c_str());
- } else {
- ASSERT_EQ(2u, cookies.size());
- cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- accounts_[GetParam().cookies[0]].email.c_str(),
- accounts_[GetParam().cookies[0]].gaia_id.c_str(),
- accounts_[GetParam().cookies[1]].email.c_str(),
- accounts_[GetParam().cookies[1]].gaia_id.c_str());
- }
+ ConfigureCookieManagerService(cookies);
// Call list accounts now so that the next call completes synchronously.
cookie_manager_service()->ListAccounts(nullptr, nullptr, "foo");
@@ -782,10 +781,16 @@ TEST_P(AccountReconcilorTestDice, TableRowTest) {
ASSERT_FALSE(reconcilor->is_reconcile_started_);
ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState());
VerifyCurrentTokens(ParseTokenString(GetParam().tokens_after_reconcile));
+
+ testing::Mock::VerifyAndClearExpectations(GetMockReconcilor());
+
// Another reconcile is sometimes triggered if Chrome accounts have changed.
// Allow it to finish.
- cookie_manager_service()->SetListAccountsResponseNoAccounts();
- cookie_manager_service()->set_list_accounts_stale_for_testing(true);
+ EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(testing::_))
+ .WillRepeatedly(testing::Return());
+ EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction())
+ .WillRepeatedly(testing::Return());
+ ConfigureCookieManagerService("");
base::RunLoop().RunUntilIdle();
}
@@ -1014,6 +1019,34 @@ TEST_F(AccountReconcilorTest, UnverifiedAccountMerge) {
ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState());
}
+// Regression test for https://crbug.com/825143
+// Checks that the primary account is not signed out when it changes during the
+// reconcile.
+TEST_F(AccountReconcilorTest, HandleSigninDuringReconcile) {
+ SetAccountConsistency(
+ signin::AccountConsistencyMethod::kDicePrepareMigration);
+
+ cookie_manager_service()->SetListAccountsResponseNoAccounts();
+ AccountReconcilor* reconcilor = GetMockReconcilor();
+ ASSERT_EQ(signin::AccountReconcilorDelegate::RevokeTokenOption::kRevoke,
+ reconcilor->delegate_->ShouldRevokeSecondaryTokensBeforeReconcile(
+ std::vector<gaia::ListedAccount>()));
+
+ // Signin during reconcile.
+ reconcilor->StartReconcile();
+ ASSERT_TRUE(reconcilor->is_reconcile_started_);
+ const std::string account_id =
+ ConnectProfileToAccount("12345", "user@gmail.com");
+ EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id)).Times(1);
+ base::RunLoop().RunUntilIdle();
+ SimulateAddAccountToCookieCompleted(reconcilor, account_id,
+ GoogleServiceAuthError::AuthErrorNone());
+ ASSERT_FALSE(reconcilor->is_reconcile_started_);
+
+ // The account has not been deleted.
+ EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id));
+}
+
// Tests that the Dice migration happens after a no-op reconcile.
TEST_F(AccountReconcilorTest, DiceMigrationAfterNoop) {
// Enable Dice migration.
@@ -1456,6 +1489,60 @@ TEST_F(AccountReconcilorTest, StartReconcileAddToCookie) {
testing::ContainerEq(expected_counts));
}
+TEST_F(AccountReconcilorTest, AuthErrorTriggersListAccount) {
+ class TestGaiaCookieObserver : public GaiaCookieManagerService::Observer {
+ public:
+ void OnGaiaAccountsInCookieUpdated(
+ const std::vector<gaia::ListedAccount>& accounts,
+ const std::vector<gaia::ListedAccount>& signed_out_accounts,
+ const GoogleServiceAuthError& error) override {
+ cookies_updated_ = true;
+ }
+
+ bool cookies_updated_ = false;
+ };
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+ signin::AccountConsistencyMethod account_consistency =
+ signin::AccountConsistencyMethod::kDice;
+ SetAccountConsistency(account_consistency);
+#else
+ signin::AccountConsistencyMethod account_consistency =
+ signin::AccountConsistencyMethod::kMirror;
+ SetAccountConsistency(account_consistency);
+#endif
+
+ // Add one account to Chrome and instantiate the reconcilor.
+ const std::string account_id =
+ ConnectProfileToAccount("12345", "user@gmail.com");
+ token_service()->UpdateCredentials(account_id, "refresh_token");
+ TestGaiaCookieObserver observer;
+ cookie_manager_service()->AddObserver(&observer);
+ AccountReconcilor* reconcilor = GetMockReconcilor();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_FALSE(reconcilor->is_reconcile_started_);
+ cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
+ "12345");
+ if (account_consistency == signin::AccountConsistencyMethod::kDice) {
+ EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction())
+ .Times(1);
+ }
+
+ // Set an authentication error.
+ ASSERT_FALSE(observer.cookies_updated_);
+ token_service()->UpdateAuthErrorForTesting(
+ account_id, GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_SERVER));
+ base::RunLoop().RunUntilIdle();
+
+ // Check that a call to ListAccount was triggered.
+ EXPECT_TRUE(observer.cookies_updated_);
+ testing::Mock::VerifyAndClearExpectations(GetMockReconcilor());
+
+ cookie_manager_service()->RemoveObserver(&observer);
+}
+
#if !defined(OS_CHROMEOS)
// This test does not run on ChromeOS because it calls
// FakeSigninManagerForTesting::SignOut() which doesn't exist for ChromeOS.
@@ -1807,7 +1894,7 @@ TEST_F(AccountReconcilorTest, NoLoopWithBadPrimary) {
// Now that we've tried once, the token service knows that the primary
// account has an auth error.
- token_service_delegate()->SetLastErrorForAccount(account_id1, error);
+ token_service()->UpdateAuthErrorForTesting(account_id1, error);
// A second attempt to reconcile should be a noop.
reconcilor->StartReconcile();
@@ -1826,7 +1913,7 @@ TEST_F(AccountReconcilorTest, WontMergeAccountsWithError) {
token_service()->UpdateCredentials(account_id2, "refresh_token");
// Mark the secondary account in auth error state.
- token_service_delegate()->SetLastErrorForAccount(
+ token_service()->UpdateAuthErrorForTesting(
account_id2,
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
diff --git a/chromium/components/signin/core/browser/android/BUILD.gn b/chromium/components/signin/core/browser/android/BUILD.gn
index 2c571ace8a7..ad4424314ee 100644
--- a/chromium/components/signin/core/browser/android/BUILD.gn
+++ b/chromium/components/signin/core/browser/android/BUILD.gn
@@ -30,6 +30,7 @@ android_library("java") {
"java/src/org/chromium/components/signin/AccountsChangeObserver.java",
"java/src/org/chromium/components/signin/AuthException.java",
"java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java",
+ "java/src/org/chromium/components/signin/ChildAccountStatus.java",
"java/src/org/chromium/components/signin/ChromeSigninController.java",
"java/src/org/chromium/components/signin/GmsAvailabilityException.java",
"java/src/org/chromium/components/signin/GmsJustUpdatedException.java",
diff --git a/chromium/components/signin/core/browser/child_account_info_fetcher_android.h b/chromium/components/signin/core/browser/child_account_info_fetcher_android.h
index aee7ed9a473..0b73cce4592 100644
--- a/chromium/components/signin/core/browser/child_account_info_fetcher_android.h
+++ b/chromium/components/signin/core/browser/child_account_info_fetcher_android.h
@@ -9,7 +9,6 @@
#include <string>
#include "base/android/scoped_java_ref.h"
-#include "base/memory/ptr_util.h"
#include "components/signin/core/browser/child_account_info_fetcher.h"
class AccountFetcherService;
diff --git a/chromium/components/signin/core/browser/cookie_settings_util.cc b/chromium/components/signin/core/browser/cookie_settings_util.cc
new file mode 100644
index 00000000000..5423303500f
--- /dev/null
+++ b/chromium/components/signin/core/browser/cookie_settings_util.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 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/signin/core/browser/cookie_settings_util.h"
+
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "url/gurl.h"
+
+namespace signin {
+
+bool SettingsAllowSigninCookies(
+ const content_settings::CookieSettings* cookie_settings) {
+ GURL gaia_url = GaiaUrls::GetInstance()->gaia_url();
+ GURL google_url = GaiaUrls::GetInstance()->google_url();
+ return cookie_settings &&
+ cookie_settings->IsCookieAccessAllowed(gaia_url, gaia_url) &&
+ cookie_settings->IsCookieAccessAllowed(google_url, google_url);
+}
+
+bool SettingsDeleteSigninCookiesOnExit(
+ const content_settings::CookieSettings* cookie_settings) {
+ GURL gaia_url = GaiaUrls::GetInstance()->gaia_url();
+ GURL google_url = GaiaUrls::GetInstance()->google_url();
+ ContentSettingsForOneType settings;
+ cookie_settings->GetCookieSettings(&settings);
+
+ return !cookie_settings ||
+ cookie_settings->ShouldDeleteCookieOnExit(
+ settings, "." + gaia_url.host(), true) ||
+ cookie_settings->ShouldDeleteCookieOnExit(
+ settings, "." + google_url.host(), true);
+}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/cookie_settings_util.h b/chromium/components/signin/core/browser/cookie_settings_util.h
new file mode 100644
index 00000000000..d2fdcd45a79
--- /dev/null
+++ b/chromium/components/signin/core/browser/cookie_settings_util.h
@@ -0,0 +1,24 @@
+// Copyright 2018 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_SIGNIN_CORE_BROWSER_COOKIE_SETTINGS_UTIL_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_COOKIE_SETTINGS_UTIL_H_
+
+namespace content_settings {
+class CookieSettings;
+}
+
+namespace signin {
+
+// Returns true if signin cookies are allowed.
+bool SettingsAllowSigninCookies(
+ const content_settings::CookieSettings* cookie_settings);
+
+// Returns true if signin cookies are cleared on exit.
+bool SettingsDeleteSigninCookiesOnExit(
+ const content_settings::CookieSettings* cookie_settings);
+
+} // namespace signin
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_COOKIE_SETTINGS_UTIL_H_
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
index eeadbe97c15..9da846066c5 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
@@ -100,16 +100,22 @@ std::string DiceAccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
return std::string();
}
-bool DiceAccountReconcilorDelegate::
- ShouldRevokeAllSecondaryTokensBeforeReconcile(
- const std::vector<gaia::ListedAccount>& gaia_accounts) {
+AccountReconcilorDelegate::RevokeTokenOption
+DiceAccountReconcilorDelegate::ShouldRevokeSecondaryTokensBeforeReconcile(
+ const std::vector<gaia::ListedAccount>& gaia_accounts) {
// During the Dice migration step, before Dice is actually enabled, chrome
// tokens must be cleared when the cookies are cleared.
- return DiceMethodGreaterOrEqual(
- account_consistency_,
- AccountConsistencyMethod::kDicePrepareMigration) &&
- (account_consistency_ != AccountConsistencyMethod::kDice) &&
- gaia_accounts.empty();
+ if (DiceMethodGreaterOrEqual(
+ account_consistency_,
+ AccountConsistencyMethod::kDicePrepareMigration) &&
+ (account_consistency_ != AccountConsistencyMethod::kDice) &&
+ gaia_accounts.empty()) {
+ return RevokeTokenOption::kRevoke;
+ }
+
+ return (account_consistency_ == AccountConsistencyMethod::kDice)
+ ? RevokeTokenOption::kRevokeIfInError
+ : RevokeTokenOption::kDoNotRevoke;
}
void DiceAccountReconcilorDelegate::OnReconcileFinished(
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
index 7acc62604fd..b4cb70586b2 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
@@ -30,7 +30,7 @@ class DiceAccountReconcilorDelegate : public AccountReconcilorDelegate {
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
bool first_execution) const override;
- bool ShouldRevokeAllSecondaryTokensBeforeReconcile(
+ RevokeTokenOption ShouldRevokeSecondaryTokensBeforeReconcile(
const std::vector<gaia::ListedAccount>& gaia_accounts) override;
void OnReconcileFinished(const std::string& first_account,
bool reconcile_is_noop) override;
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc
index 784dcddb25f..78ef2db7cbe 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate_unittest.cc
@@ -33,11 +33,13 @@ TEST(DiceAccountReconcilorDelegateTest, RevokeTokens) {
sync_preferences::TestingPrefServiceSyncable pref_service;
TestSigninClient client(&pref_service);
{
- // Dice is enabled, don't revoke.
+ // Dice is enabled, revoke only tokens in error state.
DiceAccountReconcilorDelegate delegate(&client,
AccountConsistencyMethod::kDice);
- EXPECT_FALSE(delegate.ShouldRevokeAllSecondaryTokensBeforeReconcile(
- std::vector<gaia::ListedAccount>()));
+ EXPECT_EQ(
+ signin::AccountReconcilorDelegate::RevokeTokenOption::kRevokeIfInError,
+ delegate.ShouldRevokeSecondaryTokensBeforeReconcile(
+ std::vector<gaia::ListedAccount>()));
}
{
DiceAccountReconcilorDelegate delegate(
@@ -45,11 +47,14 @@ TEST(DiceAccountReconcilorDelegateTest, RevokeTokens) {
// Gaia accounts are not empty, don't revoke.
gaia::ListedAccount gaia_account;
gaia_account.id = "other";
- EXPECT_FALSE(delegate.ShouldRevokeAllSecondaryTokensBeforeReconcile(
- std::vector<gaia::ListedAccount>{gaia_account}));
+ EXPECT_EQ(
+ signin::AccountReconcilorDelegate::RevokeTokenOption::kDoNotRevoke,
+ delegate.ShouldRevokeSecondaryTokensBeforeReconcile(
+ std::vector<gaia::ListedAccount>{gaia_account}));
// Revoke.
- EXPECT_TRUE(delegate.ShouldRevokeAllSecondaryTokensBeforeReconcile(
- std::vector<gaia::ListedAccount>()));
+ EXPECT_EQ(signin::AccountReconcilorDelegate::RevokeTokenOption::kRevoke,
+ delegate.ShouldRevokeSecondaryTokensBeforeReconcile(
+ std::vector<gaia::ListedAccount>()));
}
}
diff --git a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
index e7416d1acf2..897b8739b66 100644
--- a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
@@ -4,7 +4,6 @@
#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
-#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "google_apis/gaia/gaia_constants.h"
diff --git a/chromium/components/signin/core/browser/fake_profile_oauth2_token_service.cc b/chromium/components/signin/core/browser/fake_profile_oauth2_token_service.cc
index e8a19250234..9710636cf6e 100644
--- a/chromium/components/signin/core/browser/fake_profile_oauth2_token_service.cc
+++ b/chromium/components/signin/core/browser/fake_profile_oauth2_token_service.cc
@@ -35,6 +35,7 @@ void FakeProfileOAuth2TokenService::IssueAllTokensForAccount(
const std::string& account_id,
const std::string& access_token,
const base::Time& expiration) {
+ DCHECK(!auto_post_fetch_response_on_message_loop_);
CompleteRequests(account_id, true, ScopeSet(),
GoogleServiceAuthError::AuthErrorNone(), access_token,
expiration);
@@ -43,6 +44,7 @@ void FakeProfileOAuth2TokenService::IssueAllTokensForAccount(
void FakeProfileOAuth2TokenService::IssueErrorForAllPendingRequestsForAccount(
const std::string& account_id,
const GoogleServiceAuthError& error) {
+ DCHECK(!auto_post_fetch_response_on_message_loop_);
CompleteRequests(account_id, true, ScopeSet(), error, std::string(),
base::Time());
}
@@ -51,6 +53,7 @@ void FakeProfileOAuth2TokenService::IssueTokenForScope(
const ScopeSet& scope,
const std::string& access_token,
const base::Time& expiration) {
+ DCHECK(!auto_post_fetch_response_on_message_loop_);
CompleteRequests("", false, scope, GoogleServiceAuthError::AuthErrorNone(),
access_token, expiration);
}
@@ -58,22 +61,31 @@ void FakeProfileOAuth2TokenService::IssueTokenForScope(
void FakeProfileOAuth2TokenService::IssueErrorForScope(
const ScopeSet& scope,
const GoogleServiceAuthError& error) {
+ DCHECK(!auto_post_fetch_response_on_message_loop_);
CompleteRequests("", false, scope, error, std::string(), base::Time());
}
void FakeProfileOAuth2TokenService::IssueErrorForAllPendingRequests(
const GoogleServiceAuthError& error) {
+ DCHECK(!auto_post_fetch_response_on_message_loop_);
CompleteRequests("", true, ScopeSet(), error, std::string(), base::Time());
}
void FakeProfileOAuth2TokenService::IssueTokenForAllPendingRequests(
const std::string& access_token,
const base::Time& expiration) {
+ DCHECK(!auto_post_fetch_response_on_message_loop_);
CompleteRequests("", true, ScopeSet(),
GoogleServiceAuthError::AuthErrorNone(), access_token,
expiration);
}
+void FakeProfileOAuth2TokenService::UpdateAuthErrorForTesting(
+ const std::string& account_id,
+ const GoogleServiceAuthError& error) {
+ ProfileOAuth2TokenService::UpdateAuthError(account_id, error);
+}
+
void FakeProfileOAuth2TokenService::CompleteRequests(
const std::string& account_id,
bool all_scopes,
@@ -125,9 +137,11 @@ void FakeProfileOAuth2TokenService::FetchOAuth2Token(
if (auto_post_fetch_response_on_message_loop_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::Bind(&FakeProfileOAuth2TokenService::IssueAllTokensForAccount,
- weak_ptr_factory_.GetWeakPtr(), account_id, "access_token",
- base::Time::Max()));
+ base::BindOnce(&FakeProfileOAuth2TokenService::CompleteRequests,
+ weak_ptr_factory_.GetWeakPtr(), account_id,
+ /*all_scoped=*/true, ScopeSet(),
+ GoogleServiceAuthError::AuthErrorNone(), "access_token",
+ base::Time::Max()));
}
}
diff --git a/chromium/components/signin/core/browser/fake_profile_oauth2_token_service.h b/chromium/components/signin/core/browser/fake_profile_oauth2_token_service.h
index f2301fdbd80..9edcd086071 100644
--- a/chromium/components/signin/core/browser/fake_profile_oauth2_token_service.h
+++ b/chromium/components/signin/core/browser/fake_profile_oauth2_token_service.h
@@ -81,6 +81,10 @@ class FakeProfileOAuth2TokenService : public ProfileOAuth2TokenService {
auto_post_fetch_response_on_message_loop_ = auto_post_response;
}
+ // Calls ProfileOAuth2TokenService::UpdateAuthError(). Exposed for testing.
+ void UpdateAuthErrorForTesting(const std::string& account_id,
+ const GoogleServiceAuthError& error);
+
protected:
// OAuth2TokenService overrides.
void FetchOAuth2Token(RequestImpl* request,
diff --git a/chromium/components/signin/core/browser/fake_signin_manager.cc b/chromium/components/signin/core/browser/fake_signin_manager.cc
index ab4c9747d9c..a59df220373 100644
--- a/chromium/components/signin/core/browser/fake_signin_manager.cc
+++ b/chromium/components/signin/core/browser/fake_signin_manager.cc
@@ -88,7 +88,7 @@ void FakeSigninManager::FailSignin(const GoogleServiceAuthError& error) {
void FakeSigninManager::DoSignOut(
signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric,
- bool remove_all_accounts) {
+ RemoveAccountsOption remove_option) {
if (IsSignoutProhibited())
return;
set_auth_in_progress(std::string());
@@ -97,8 +97,19 @@ void FakeSigninManager::DoSignOut(
const std::string account_id = GetAuthenticatedAccountId();
const std::string username = account_info.email;
authenticated_account_id_.clear();
- if (token_service_ && remove_all_accounts)
- token_service_->RevokeAllCredentials();
+ switch (remove_option) {
+ case RemoveAccountsOption::kRemoveAllAccounts:
+ if (token_service_)
+ token_service_->RevokeAllCredentials();
+ break;
+ case RemoveAccountsOption::kRemoveAuthenticatedAccountIfInError:
+ if (token_service_ && token_service_->RefreshTokenHasError(account_id))
+ token_service_->RevokeCredentials(account_id);
+ break;
+ case RemoveAccountsOption::kKeepAllAccounts:
+ // Do nothing.
+ break;
+ }
FireGoogleSignedOut(account_id, account_info);
}
diff --git a/chromium/components/signin/core/browser/fake_signin_manager.h b/chromium/components/signin/core/browser/fake_signin_manager.h
index 26cc7f8289e..3f3e9cee7a1 100644
--- a/chromium/components/signin/core/browser/fake_signin_manager.h
+++ b/chromium/components/signin/core/browser/fake_signin_manager.h
@@ -66,7 +66,7 @@ class FakeSigninManager : public SigninManager {
protected:
void DoSignOut(signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric,
- bool remove_all_accounts) override;
+ RemoveAccountsOption remove_option) override;
// Username specified in StartSignInWithRefreshToken() call.
std::string username_;
diff --git a/chromium/components/signin/core/browser/profile_management_switches.cc b/chromium/components/signin/core/browser/profile_management_switches.cc
index 851bf9f851b..a26592c75da 100644
--- a/chromium/components/signin/core/browser/profile_management_switches.cc
+++ b/chromium/components/signin/core/browser/profile_management_switches.cc
@@ -12,7 +12,7 @@
#include "base/metrics/field_trial_params.h"
#include "build/build_config.h"
#include "components/pref_registry/pref_registry_syncable.h"
-#include "components/signin/core/browser/signin_features.h"
+#include "components/signin/core/browser/signin_buildflags.h"
#include "components/signin/core/browser/signin_switches.h"
#if defined(OS_CHROMEOS)
@@ -74,6 +74,9 @@ const char kAccountConsistencyFeatureMethodDicePrepareMigration[] =
const char kAccountConsistencyFeatureMethodDiceMigration[] = "dice_migration";
const char kAccountConsistencyFeatureMethodDice[] = "dice";
+const base::Feature kUnifiedConsent{"UnifiedConsent",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
bool DiceMethodGreaterOrEqual(AccountConsistencyMethod a,
AccountConsistencyMethod b) {
DCHECK_NE(AccountConsistencyMethod::kMirror, a);
@@ -116,7 +119,10 @@ AccountConsistencyMethod GetAccountConsistencyMethod() {
std::string method_value = base::GetFieldTrialParamValueByFeature(
kAccountConsistencyFeature, kAccountConsistencyFeatureMethodParameter);
- if (method_value == kAccountConsistencyFeatureMethodDiceFixAuthErrors)
+ if (method_value == kAccountConsistencyFeatureMethodMirror)
+ return AccountConsistencyMethod::kMirror;
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+ else if (method_value == kAccountConsistencyFeatureMethodDiceFixAuthErrors)
return AccountConsistencyMethod::kDiceFixAuthErrors;
else if (method_value == kAccountConsistencyFeatureMethodDicePrepareMigration)
return AccountConsistencyMethod::kDicePrepareMigration;
@@ -124,8 +130,7 @@ AccountConsistencyMethod GetAccountConsistencyMethod() {
return AccountConsistencyMethod::kDiceMigration;
else if (method_value == kAccountConsistencyFeatureMethodDice)
return AccountConsistencyMethod::kDice;
- else if (method_value == kAccountConsistencyFeatureMethodMirror)
- return AccountConsistencyMethod::kMirror;
+#endif
return kDefaultMethod;
}
diff --git a/chromium/components/signin/core/browser/profile_management_switches.h b/chromium/components/signin/core/browser/profile_management_switches.h
index 330a1a37a13..abc74d67ade 100644
--- a/chromium/components/signin/core/browser/profile_management_switches.h
+++ b/chromium/components/signin/core/browser/profile_management_switches.h
@@ -37,6 +37,9 @@ extern const char kAccountConsistencyFeatureMethodDicePrepareMigration[];
extern const char kAccountConsistencyFeatureMethodDiceMigration[];
extern const char kAccountConsistencyFeatureMethodDice[];
+// Improved and unified consent for privacy-related features.
+extern const base::Feature kUnifiedConsent;
+
// TODO(https://crbug.com/777774): Cleanup this enum and remove related
// functions once Dice is fully rolled out, and/or Mirror code is removed on
// desktop.
diff --git a/chromium/components/signin/core/browser/profile_management_switches_unittest.cc b/chromium/components/signin/core/browser/profile_management_switches_unittest.cc
index 8aa9c2b2907..c0f40463050 100644
--- a/chromium/components/signin/core/browser/profile_management_switches_unittest.cc
+++ b/chromium/components/signin/core/browser/profile_management_switches_unittest.cc
@@ -11,7 +11,7 @@
#include "base/message_loop/message_loop.h"
#include "components/prefs/pref_member.h"
#include "components/signin/core/browser/scoped_account_consistency.h"
-#include "components/signin/core/browser/signin_features.h"
+#include "components/signin/core/browser/signin_buildflags.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/signin/core/browser/scoped_account_consistency.cc b/chromium/components/signin/core/browser/scoped_account_consistency.cc
index 952a08f0188..820386156d7 100644
--- a/chromium/components/signin/core/browser/scoped_account_consistency.cc
+++ b/chromium/components/signin/core/browser/scoped_account_consistency.cc
@@ -12,7 +12,7 @@
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/test/scoped_feature_list.h"
-#include "components/signin/core/browser/signin_features.h"
+#include "components/signin/core/browser/signin_buildflags.h"
namespace signin {
diff --git a/chromium/components/signin/core/browser/signin_error_controller.cc b/chromium/components/signin/core/browser/signin_error_controller.cc
index c9d53d0f29f..312037770f0 100644
--- a/chromium/components/signin/core/browser/signin_error_controller.cc
+++ b/chromium/components/signin/core/browser/signin_error_controller.cc
@@ -96,7 +96,7 @@ void SigninErrorController::AuthStatusChanged() {
}
if (error_changed) {
- signin_metrics::LogAuthError(auth_error_.state());
+ signin_metrics::LogAuthError(auth_error_);
for (auto& observer : observer_list_)
observer.OnErrorChanged();
}
diff --git a/chromium/components/signin/core/browser/signin_header_helper.cc b/chromium/components/signin/core/browser/signin_header_helper.cc
index 6c5a0eca4aa..720d7266f01 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper.cc
@@ -9,11 +9,10 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_split.h"
-#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/google/core/browser/google_util.h"
#include "components/signin/core/browser/chrome_connected_header_helper.h"
+#include "components/signin/core/browser/cookie_settings_util.h"
#include "google_apis/gaia/gaia_auth_util.h"
-#include "google_apis/gaia/gaia_urls.h"
#include "net/base/escape.h"
#include "net/url_request/url_request.h"
@@ -66,15 +65,6 @@ DiceResponseParams::EnableSyncInfo::~EnableSyncInfo() {}
DiceResponseParams::EnableSyncInfo::EnableSyncInfo(const EnableSyncInfo&) =
default;
-bool SettingsAllowSigninCookies(
- const content_settings::CookieSettings* cookie_settings) {
- GURL gaia_url = GaiaUrls::GetInstance()->gaia_url();
- GURL google_url = GaiaUrls::GetInstance()->google_url();
- return cookie_settings &&
- cookie_settings->IsCookieAccessAllowed(gaia_url, gaia_url) &&
- cookie_settings->IsCookieAccessAllowed(google_url, google_url);
-}
-
std::string BuildMirrorRequestCookieIfPossible(
const GURL& url,
const std::string& account_id,
diff --git a/chromium/components/signin/core/browser/signin_header_helper.h b/chromium/components/signin/core/browser/signin_header_helper.h
index 2d0f0b2ae49..7e10bf1fc28 100644
--- a/chromium/components/signin/core/browser/signin_header_helper.h
+++ b/chromium/components/signin/core/browser/signin_header_helper.h
@@ -11,7 +11,7 @@
#include "components/prefs/pref_member.h"
#include "components/signin/core/browser/profile_management_switches.h"
-#include "components/signin/core/browser/signin_features.h"
+#include "components/signin/core/browser/signin_buildflags.h"
#include "url/gurl.h"
namespace content_settings {
@@ -178,9 +178,6 @@ class SigninHeaderHelper {
virtual bool IsUrlEligibleForRequestHeader(const GURL& url) = 0;
};
-// Returns true if signin cookies are allowed.
-bool SettingsAllowSigninCookies(
- const content_settings::CookieSettings* cookie_settings);
// Returns the CHROME_CONNECTED cookie, or an empty string if it should not be
// added to the request to |url|.
diff --git a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
index 9056b83e57f..870bd70ce0b 100644
--- a/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_header_helper_unittest.cc
@@ -14,7 +14,7 @@
#include "components/prefs/pref_member.h"
#include "components/signin/core/browser/chrome_connected_header_helper.h"
#include "components/signin/core/browser/profile_management_switches.h"
-#include "components/signin/core/browser/signin_features.h"
+#include "components/signin/core/browser/signin_buildflags.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
diff --git a/chromium/components/signin/core/browser/signin_manager.cc b/chromium/components/signin/core/browser/signin_manager.cc
index a7460b60024..5b92a3473b2 100644
--- a/chromium/components/signin/core/browser/signin_manager.cc
+++ b/chromium/components/signin/core/browser/signin_manager.cc
@@ -160,38 +160,41 @@ void SigninManager::HandleAuthError(const GoogleServiceAuthError& error) {
void SigninManager::SignOut(
signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric) {
- StartSignOut(signout_source_metric, signout_delete_metric,
- account_consistency_ != signin::AccountConsistencyMethod::kDice);
+ RemoveAccountsOption remove_option =
+ (account_consistency_ == signin::AccountConsistencyMethod::kDice)
+ ? RemoveAccountsOption::kRemoveAuthenticatedAccountIfInError
+ : RemoveAccountsOption::kRemoveAllAccounts;
+ StartSignOut(signout_source_metric, signout_delete_metric, remove_option);
}
void SigninManager::SignOutAndRemoveAllAccounts(
signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric) {
StartSignOut(signout_source_metric, signout_delete_metric,
- true /* remove_all_tokens */);
+ RemoveAccountsOption::kRemoveAllAccounts);
}
void SigninManager::SignOutAndKeepAllAccounts(
signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric) {
StartSignOut(signout_source_metric, signout_delete_metric,
- false /* remove_all_tokens */);
+ RemoveAccountsOption::kKeepAllAccounts);
}
void SigninManager::StartSignOut(
signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric,
- bool remove_all_accounts) {
- client_->PreSignOut(base::Bind(&SigninManager::DoSignOut,
- base::Unretained(this), signout_source_metric,
- signout_delete_metric, remove_all_accounts),
- signout_source_metric);
+ RemoveAccountsOption remove_option) {
+ client_->PreSignOut(
+ base::Bind(&SigninManager::DoSignOut, base::Unretained(this),
+ signout_source_metric, signout_delete_metric, remove_option),
+ signout_source_metric);
}
void SigninManager::DoSignOut(
signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric,
- bool remove_all_accounts) {
+ RemoveAccountsOption remove_option) {
DCHECK(IsInitialized());
signin_metrics::LogSignout(signout_source_metric, signout_delete_metric);
@@ -241,10 +244,19 @@ void SigninManager::DoSignOut(
// Revoke all tokens before sending signed_out notification, because there
// may be components that don't listen for token service events when the
// profile is not connected to an account.
- if (remove_all_accounts) {
- LOG(WARNING) << "Revoking all refresh tokens on server. Reason: sign out, "
- << "IsSigninAllowed: " << IsSigninAllowed();
- token_service_->RevokeAllCredentials();
+ switch (remove_option) {
+ case RemoveAccountsOption::kRemoveAllAccounts:
+ VLOG(0) << "Revoking all refresh tokens on server. Reason: sign out, "
+ << "IsSigninAllowed: " << IsSigninAllowed();
+ token_service_->RevokeAllCredentials();
+ break;
+ case RemoveAccountsOption::kRemoveAuthenticatedAccountIfInError:
+ if (token_service_->RefreshTokenHasError(account_id))
+ token_service_->RevokeCredentials(account_id);
+ break;
+ case RemoveAccountsOption::kKeepAllAccounts:
+ // Do nothing.
+ break;
}
FireGoogleSignedOut(account_id, account_info);
diff --git a/chromium/components/signin/core/browser/signin_manager.h b/chromium/components/signin/core/browser/signin_manager.h
index 72f26974c6f..8b7d54cf9a8 100644
--- a/chromium/components/signin/core/browser/signin_manager.h
+++ b/chromium/components/signin/core/browser/signin_manager.h
@@ -62,6 +62,16 @@ class SigninManager : public SigninManagerBase,
// signin. The callback is passed the just-fetched OAuth login refresh token.
typedef base::Callback<void(const std::string&)> OAuthTokenFetchedCallback;
+ // Used to remove accounts from the token service and the account tracker.
+ enum class RemoveAccountsOption {
+ // Do not remove accounts.
+ kKeepAllAccounts,
+ // Remove all the accounts.
+ kRemoveAllAccounts,
+ // Removes the authenticated account if it is in authentication error.
+ kRemoveAuthenticatedAccountIfInError
+ };
+
// This is used to distinguish URLs belonging to the special web signin flow
// running in the special signin process from other URLs on the same domain.
// We do not grant WebUI privilieges / bindings to this process or to URLs of
@@ -109,8 +119,9 @@ class SigninManager : public SigninManagerBase,
// associated with the authenticated user, and canceling all auth in progress.
// On mobile and on desktop pre-DICE, this also removes all accounts from
// Chrome by revoking all refresh tokens.
- // On desktop with DICE enabled, this will not remove all accounts from
- // Chrome.
+ // On desktop with DICE enabled, this will remove the authenticated account
+ // from Chrome only if it is in authentication error. No other accounts are
+ // removed.
void SignOut(signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric);
@@ -183,7 +194,7 @@ class SigninManager : public SigninManagerBase,
// The sign out process which is started by SigninClient::PreSignOut()
virtual void DoSignOut(signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric,
- bool remove_all_accounts);
+ RemoveAccountsOption remove_option);
private:
// Interface that gives information on internal SigninManager operations. Only
@@ -265,7 +276,7 @@ class SigninManager : public SigninManagerBase,
// Starts the sign out process.
void StartSignOut(signin_metrics::ProfileSignout signout_source_metric,
signin_metrics::SignoutDelete signout_delete_metric,
- bool remove_all_accounts);
+ RemoveAccountsOption remove_option);
void OnSigninAllowedPrefChanged();
void OnGoogleServicesUsernamePatternChanged();
diff --git a/chromium/components/signin/core/browser/signin_manager_unittest.cc b/chromium/components/signin/core/browser/signin_manager_unittest.cc
index 7fa807de9d3..1ae77c52090 100644
--- a/chromium/components/signin/core/browser/signin_manager_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_manager_unittest.cc
@@ -85,7 +85,8 @@ class SigninManagerTest : public testing::Test {
cookie_manager_service_(&token_service_,
GaiaConstants::kChromeSource,
&test_signin_client_),
- url_fetcher_factory_(nullptr) {
+ url_fetcher_factory_(nullptr),
+ account_consistency_(signin::AccountConsistencyMethod::kDisabled) {
test_signin_client_.SetURLRequestContext(
new net::TestURLRequestContextGetter(loop_.task_runner()));
cookie_manager_service_.Init(&url_fetcher_factory_);
@@ -131,7 +132,7 @@ class SigninManagerTest : public testing::Test {
manager_ = std::make_unique<SigninManager>(
&test_signin_client_, &token_service_, &account_tracker_,
&cookie_manager_service_, nullptr /* signin_error_controller */,
- signin::AccountConsistencyMethod::kDisabled);
+ account_consistency_);
manager_->Initialize(&local_state_);
manager_->AddObserver(&test_observer_);
}
@@ -176,6 +177,7 @@ class SigninManagerTest : public testing::Test {
TestSigninManagerObserver test_observer_;
std::vector<std::string> oauth_tokens_fetched_;
std::vector<std::string> cookies_;
+ signin::AccountConsistencyMethod account_consistency_;
};
TEST_F(SigninManagerTest, SignInWithRefreshToken) {
@@ -258,6 +260,79 @@ TEST_F(SigninManagerTest, SignOut) {
EXPECT_TRUE(manager_->GetAuthenticatedAccountId().empty());
}
+TEST_F(SigninManagerTest, SignOutRevoke) {
+ CreateSigninManager();
+ std::string main_account_id =
+ AddToAccountTracker("main_id", "user@gmail.com");
+ std::string other_account_id =
+ AddToAccountTracker("other_id", "other@gmail.com");
+ token_service_.UpdateCredentials(main_account_id, "token");
+ token_service_.UpdateCredentials(other_account_id, "token");
+ manager_->OnExternalSigninCompleted("user@gmail.com");
+ EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_EQ(main_account_id, manager_->GetAuthenticatedAccountId());
+
+ manager_->SignOut(signin_metrics::SIGNOUT_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+
+ // Tokens are revoked.
+ EXPECT_FALSE(manager_->IsAuthenticated());
+ EXPECT_TRUE(token_service_.GetAccounts().empty());
+}
+
+TEST_F(SigninManagerTest, SignOutDiceNoRevoke) {
+ account_consistency_ = signin::AccountConsistencyMethod::kDice;
+ CreateSigninManager();
+ std::string main_account_id =
+ AddToAccountTracker("main_id", "user@gmail.com");
+ std::string other_account_id =
+ AddToAccountTracker("other_id", "other@gmail.com");
+ token_service_.UpdateCredentials(main_account_id, "token");
+ token_service_.UpdateCredentials(other_account_id, "token");
+ manager_->OnExternalSigninCompleted("user@gmail.com");
+ EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_EQ(main_account_id, manager_->GetAuthenticatedAccountId());
+
+ manager_->SignOut(signin_metrics::SIGNOUT_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+
+ // Tokens are not revoked.
+ EXPECT_FALSE(manager_->IsAuthenticated());
+ std::vector<std::string> expected_tokens = {main_account_id,
+ other_account_id};
+ EXPECT_EQ(expected_tokens, token_service_.GetAccounts());
+}
+
+TEST_F(SigninManagerTest, SignOutDiceWithError) {
+ account_consistency_ = signin::AccountConsistencyMethod::kDice;
+ CreateSigninManager();
+ std::string main_account_id =
+ AddToAccountTracker("main_id", "user@gmail.com");
+ std::string other_account_id =
+ AddToAccountTracker("other_id", "other@gmail.com");
+ token_service_.UpdateCredentials(main_account_id, "token");
+ token_service_.UpdateCredentials(other_account_id, "token");
+ manager_->OnExternalSigninCompleted("user@gmail.com");
+
+ GoogleServiceAuthError error(
+ GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+ token_service_.UpdateAuthErrorForTesting(main_account_id, error);
+ token_service_.UpdateAuthErrorForTesting(other_account_id, error);
+ ASSERT_TRUE(token_service_.RefreshTokenHasError(main_account_id));
+ ASSERT_TRUE(token_service_.RefreshTokenHasError(other_account_id));
+
+ EXPECT_TRUE(manager_->IsAuthenticated());
+ EXPECT_EQ(main_account_id, manager_->GetAuthenticatedAccountId());
+
+ manager_->SignOut(signin_metrics::SIGNOUT_TEST,
+ signin_metrics::SignoutDelete::IGNORE_METRIC);
+
+ // Only main token is revoked.
+ EXPECT_FALSE(manager_->IsAuthenticated());
+ std::vector<std::string> expected_tokens = {other_account_id};
+ EXPECT_EQ(expected_tokens, token_service_.GetAccounts());
+}
+
TEST_F(SigninManagerTest, SignOutWhileProhibited) {
CreateSigninManager();
EXPECT_FALSE(manager_->IsAuthenticated());
diff --git a/chromium/components/signin/core/browser/signin_metrics.cc b/chromium/components/signin/core/browser/signin_metrics.cc
index 1fdbd889b95..21f5feee326 100644
--- a/chromium/components/signin/core/browser/signin_metrics.cc
+++ b/chromium/components/signin/core/browser/signin_metrics.cc
@@ -13,6 +13,304 @@
namespace signin_metrics {
+namespace {
+void RecordSigninUserActionForAccessPoint(AccessPoint access_point) {
+ switch (access_point) {
+ case AccessPoint::ACCESS_POINT_START_PAGE:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromStartPage"));
+ break;
+ case AccessPoint::ACCESS_POINT_NTP_LINK:
+ base::RecordAction(base::UserMetricsAction("Signin_Signin_FromNTP"));
+ break;
+ case AccessPoint::ACCESS_POINT_MENU:
+ base::RecordAction(base::UserMetricsAction("Signin_Signin_FromMenu"));
+ break;
+ case AccessPoint::ACCESS_POINT_SETTINGS:
+ base::RecordAction(base::UserMetricsAction("Signin_Signin_FromSettings"));
+ break;
+ case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromSupervisedUser"));
+ break;
+ case AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromExtensionInstallBubble"));
+ break;
+ case AccessPoint::ACCESS_POINT_EXTENSIONS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromExtensions"));
+ break;
+ case AccessPoint::ACCESS_POINT_APPS_PAGE_LINK:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromAppsPageLink"));
+ break;
+ case AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromBookmarkBubble"));
+ break;
+ case AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromBookmarkManager"));
+ break;
+ case AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromAvatarBubbleSignin"));
+ break;
+ case AccessPoint::ACCESS_POINT_USER_MANAGER:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromUserManager"));
+ break;
+ case AccessPoint::ACCESS_POINT_DEVICES_PAGE:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromDevicesPage"));
+ break;
+ case AccessPoint::ACCESS_POINT_CLOUD_PRINT:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromCloudPrint"));
+ break;
+ case AccessPoint::ACCESS_POINT_CONTENT_AREA:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromContentArea"));
+ break;
+ case AccessPoint::ACCESS_POINT_SIGNIN_PROMO:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromSigninPromo"));
+ break;
+ case AccessPoint::ACCESS_POINT_RECENT_TABS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromRecentTabs"));
+ break;
+ case AccessPoint::ACCESS_POINT_UNKNOWN:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromUnknownAccessPoint"));
+ break;
+ case AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromPasswordBubble"));
+ break;
+ case AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromAutofillDropdown"));
+ break;
+ case AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromNTPContentSuggestions"));
+ break;
+ case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromReSigninInfobar"));
+ break;
+ case AccessPoint::ACCESS_POINT_TAB_SWITCHER:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromTabSwitcher"));
+ break;
+ case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_Signin_FromForceSigninWarning"));
+ break;
+ case AccessPoint::ACCESS_POINT_MAX:
+ NOTREACHED();
+ break;
+ }
+}
+
+void RecordSigninWithDefaultUserActionForAccessPoint(
+ signin_metrics::AccessPoint access_point) {
+ switch (access_point) {
+ case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninWithDefault_FromSettings"));
+ break;
+ case AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninWithDefault_FromExtensionInstallBubble"));
+ break;
+ case AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninWithDefault_FromBookmarkBubble"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninWithDefault_FromBookmarkManager"));
+ break;
+ case AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninWithDefault_FromAvatarBubbleSignin"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_RECENT_TABS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninWithDefault_FromRecentTabs"));
+ break;
+ case AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninWithDefault_FromPasswordBubble"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_TAB_SWITCHER:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninWithDefault_FromTabSwitcher"));
+ break;
+ case AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninWithDefault_FromNTPContentSuggestions"));
+ break;
+ case AccessPoint::ACCESS_POINT_START_PAGE:
+ case AccessPoint::ACCESS_POINT_NTP_LINK:
+ case AccessPoint::ACCESS_POINT_MENU:
+ case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
+ case AccessPoint::ACCESS_POINT_EXTENSIONS:
+ case AccessPoint::ACCESS_POINT_APPS_PAGE_LINK:
+ case AccessPoint::ACCESS_POINT_USER_MANAGER:
+ case AccessPoint::ACCESS_POINT_DEVICES_PAGE:
+ case AccessPoint::ACCESS_POINT_CLOUD_PRINT:
+ case AccessPoint::ACCESS_POINT_CONTENT_AREA:
+ case AccessPoint::ACCESS_POINT_SIGNIN_PROMO:
+ case AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN:
+ case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
+ case AccessPoint::ACCESS_POINT_UNKNOWN:
+ case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ NOTREACHED() << "Signin_SigninWithDefault_From* user actions"
+ << " are not recorded for access_point "
+ << static_cast<int>(access_point)
+ << " as it does not support a personalized sign-in promo.";
+ break;
+ case AccessPoint::ACCESS_POINT_MAX:
+ NOTREACHED();
+ break;
+ }
+}
+
+void RecordSigninNotDefaultUserActionForAccessPoint(
+ signin_metrics::AccessPoint access_point) {
+ switch (access_point) {
+ case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninNotDefault_FromSettings"));
+ break;
+ case AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNotDefault_FromExtensionInstallBubble"));
+ break;
+ case AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNotDefault_FromBookmarkBubble"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNotDefault_FromBookmarkManager"));
+ break;
+ case AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNotDefault_FromAvatarBubbleSignin"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_RECENT_TABS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninNotDefault_FromRecentTabs"));
+ break;
+ case AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNotDefault_FromPasswordBubble"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_TAB_SWITCHER:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninNotDefault_FromTabSwitcher"));
+ break;
+ case AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNotDefault_FromNTPContentSuggestions"));
+ break;
+ case AccessPoint::ACCESS_POINT_START_PAGE:
+ case AccessPoint::ACCESS_POINT_NTP_LINK:
+ case AccessPoint::ACCESS_POINT_MENU:
+ case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
+ case AccessPoint::ACCESS_POINT_EXTENSIONS:
+ case AccessPoint::ACCESS_POINT_APPS_PAGE_LINK:
+ case AccessPoint::ACCESS_POINT_USER_MANAGER:
+ case AccessPoint::ACCESS_POINT_DEVICES_PAGE:
+ case AccessPoint::ACCESS_POINT_CLOUD_PRINT:
+ case AccessPoint::ACCESS_POINT_CONTENT_AREA:
+ case AccessPoint::ACCESS_POINT_SIGNIN_PROMO:
+ case AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN:
+ case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
+ case AccessPoint::ACCESS_POINT_UNKNOWN:
+ case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ NOTREACHED() << "Signin_SigninNotDefault_From* user actions"
+ << " are not recorded for access_point "
+ << static_cast<int>(access_point)
+ << " as it does not support a personalized sign-in promo.";
+ break;
+ case AccessPoint::ACCESS_POINT_MAX:
+ NOTREACHED();
+ break;
+ }
+}
+
+void RecordSigninNewAccountUserActionForAccessPoint(
+ signin_metrics::AccessPoint access_point) {
+ switch (access_point) {
+ case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninNewAccount_FromSettings"));
+ break;
+ case AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNewAccount_FromExtensionInstallBubble"));
+ break;
+ case AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNewAccount_FromBookmarkBubble"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNewAccount_FromBookmarkManager"));
+ break;
+ case AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNewAccount_FromAvatarBubbleSignin"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_RECENT_TABS:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninNewAccount_FromRecentTabs"));
+ break;
+ case AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNewAccount_FromPasswordBubble"));
+ break;
+ case signin_metrics::AccessPoint::ACCESS_POINT_TAB_SWITCHER:
+ base::RecordAction(
+ base::UserMetricsAction("Signin_SigninNewAccount_FromTabSwitcher"));
+ break;
+ case AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_SigninNewAccount_FromNTPContentSuggestions"));
+ break;
+ case AccessPoint::ACCESS_POINT_START_PAGE:
+ case AccessPoint::ACCESS_POINT_NTP_LINK:
+ case AccessPoint::ACCESS_POINT_MENU:
+ case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
+ case AccessPoint::ACCESS_POINT_EXTENSIONS:
+ case AccessPoint::ACCESS_POINT_APPS_PAGE_LINK:
+ case AccessPoint::ACCESS_POINT_USER_MANAGER:
+ case AccessPoint::ACCESS_POINT_DEVICES_PAGE:
+ case AccessPoint::ACCESS_POINT_CLOUD_PRINT:
+ case AccessPoint::ACCESS_POINT_CONTENT_AREA:
+ case AccessPoint::ACCESS_POINT_SIGNIN_PROMO:
+ case AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN:
+ case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
+ case AccessPoint::ACCESS_POINT_UNKNOWN:
+ case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ NOTREACHED() << "Signin_SigninNewAccount_From* user actions"
+ << " are not recorded for access_point "
+ << static_cast<int>(access_point)
+ << " as it does not support a personalized sign-in promo.";
+ break;
+ case AccessPoint::ACCESS_POINT_MAX:
+ NOTREACHED();
+ break;
+ }
+}
+} // namespace
+
// These intermediate macros are necessary when we may emit to different
// histograms from the same logical place in the code. The base histogram macros
// expand in a way that can only work for a single histogram name, so these
@@ -60,16 +358,6 @@ DifferentPrimaryAccounts ComparePrimaryAccounts(bool primary_accounts_same,
return COOKIE_AND_TOKEN_PRIMARIES_DIFFERENT;
}
-void LogSigninAccessPointStarted(AccessPoint access_point) {
- LogSigninAccessPointStarted(
- access_point, signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO);
-}
-
-void LogSigninAccessPointCompleted(AccessPoint access_point) {
- LogSigninAccessPointCompleted(
- access_point, signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO);
-}
-
void LogSigninAccessPointStarted(AccessPoint access_point,
PromoAction promo_action) {
UMA_HISTOGRAM_ENUMERATION("Signin.SigninStartedAccessPoint",
@@ -219,14 +507,20 @@ void LogExternalCcResultFetches(
}
}
-void LogAuthError(GoogleServiceAuthError::State auth_error) {
- UMA_HISTOGRAM_ENUMERATION("Signin.AuthError", auth_error,
- GoogleServiceAuthError::State::NUM_STATES);
+void LogAuthError(const GoogleServiceAuthError& auth_error) {
+ UMA_HISTOGRAM_ENUMERATION("Signin.AuthError", auth_error.state(),
+ GoogleServiceAuthError::State::NUM_STATES);
+ if (auth_error.state() == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Signin.InvalidGaiaCredentialsReason",
+ auth_error.GetInvalidGaiaCredentialsReason(),
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::NUM_REASONS);
+ }
}
void LogSigninConfirmHistogramValue(ConfirmationUsage action) {
UMA_HISTOGRAM_ENUMERATION("Signin.OneClickConfirmation", action,
- signin_metrics::HISTOGRAM_CONFIRM_MAX);
+ HISTOGRAM_CONFIRM_MAX);
}
void LogXDevicePromoEligible(CrossDevicePromoEligibility metric) {
@@ -294,103 +588,218 @@ void LogIsShared(const bool is_shared, const ReportingType type) {
// User actions
// --------------------------------------------------------------
-void RecordSigninUserActionForAccessPoint(
- signin_metrics::AccessPoint access_point) {
- switch (access_point) {
- case signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE:
- base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromStartPage"));
+void RecordSigninUserActionForAccessPoint(AccessPoint access_point,
+ PromoAction promo_action) {
+ RecordSigninUserActionForAccessPoint(access_point);
+ switch (promo_action) {
+ case PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO:
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_NTP_LINK:
- base::RecordAction(base::UserMetricsAction("Signin_Signin_FromNTP"));
+ case PromoAction::PROMO_ACTION_WITH_DEFAULT:
+ RecordSigninWithDefaultUserActionForAccessPoint(access_point);
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_MENU:
- base::RecordAction(base::UserMetricsAction("Signin_Signin_FromMenu"));
+ case PromoAction::PROMO_ACTION_NOT_DEFAULT:
+ RecordSigninNotDefaultUserActionForAccessPoint(access_point);
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS:
- base::RecordAction(base::UserMetricsAction("Signin_Signin_FromSettings"));
+ case PromoAction::PROMO_ACTION_NEW_ACCOUNT:
+ RecordSigninNewAccountUserActionForAccessPoint(access_point);
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_SUPERVISED_USER:
+ }
+}
+
+void RecordSigninImpressionUserActionForAccessPoint(AccessPoint access_point) {
+ switch (access_point) {
+ case AccessPoint::ACCESS_POINT_START_PAGE:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromSupervisedUser"));
+ base::UserMetricsAction("Signin_Impression_FromStartPage"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE:
- base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromExtensionInstallBubble"));
+ case AccessPoint::ACCESS_POINT_NTP_LINK:
+ base::RecordAction(base::UserMetricsAction("Signin_Impression_FromNTP"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_EXTENSIONS:
- base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromExtensions"));
+ case AccessPoint::ACCESS_POINT_MENU:
+ base::RecordAction(base::UserMetricsAction("Signin_Impression_FromMenu"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_APPS_PAGE_LINK:
+ case AccessPoint::ACCESS_POINT_SETTINGS:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromAppsPageLink"));
+ base::UserMetricsAction("Signin_Impression_FromSettings"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE:
- base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromBookmarkBubble"));
+ case AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_Impression_FromExtensionInstallBubble"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+ case AccessPoint::ACCESS_POINT_APPS_PAGE_LINK:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromBookmarkManager"));
+ base::UserMetricsAction("Signin_Impression_FromAppsPageLink"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN:
+ case AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromAvatarBubbleSignin"));
+ base::UserMetricsAction("Signin_Impression_FromBookmarkBubble"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_USER_MANAGER:
+ case AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromUserManager"));
+ base::UserMetricsAction("Signin_Impression_FromBookmarkManager"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_DEVICES_PAGE:
+ case AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromDevicesPage"));
- break;
- case signin_metrics::AccessPoint::ACCESS_POINT_CLOUD_PRINT:
- base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromCloudPrint"));
- break;
- case signin_metrics::AccessPoint::ACCESS_POINT_CONTENT_AREA:
- base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromContentArea"));
+ base::UserMetricsAction("Signin_Impression_FromAvatarBubbleSignin"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_SIGNIN_PROMO:
+ case AccessPoint::ACCESS_POINT_DEVICES_PAGE:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromSigninPromo"));
+ base::UserMetricsAction("Signin_Impression_FromDevicesPage"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_RECENT_TABS:
+ case AccessPoint::ACCESS_POINT_CLOUD_PRINT:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromRecentTabs"));
+ base::UserMetricsAction("Signin_Impression_FromCloudPrint"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_UNKNOWN:
+ case AccessPoint::ACCESS_POINT_SIGNIN_PROMO:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromUnknownAccessPoint"));
+ base::UserMetricsAction("Signin_Impression_FromSigninPromo"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE:
+ case AccessPoint::ACCESS_POINT_RECENT_TABS:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromPasswordBubble"));
+ base::UserMetricsAction("Signin_Impression_FromRecentTabs"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN:
+ case AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromAutofillDropdown"));
+ base::UserMetricsAction("Signin_Impression_FromPasswordBubble"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS:
+ case AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromNTPContentSuggestions"));
+ base::UserMetricsAction("Signin_Impression_FromAutofillDropdown"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
- base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromReSigninInfobar"));
+ case AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS:
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_Impression_FromNTPContentSuggestions"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_TAB_SWITCHER:
+ case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromTabSwitcher"));
+ base::UserMetricsAction("Signin_Impression_FromReSigninInfobar"));
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ case AccessPoint::ACCESS_POINT_TAB_SWITCHER:
base::RecordAction(
- base::UserMetricsAction("Signin_Signin_FromForceSigninWarning"));
+ base::UserMetricsAction("Signin_Impression_FromTabSwitcher"));
+ break;
+ case AccessPoint::ACCESS_POINT_CONTENT_AREA:
+ case AccessPoint::ACCESS_POINT_EXTENSIONS:
+ case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
+ case AccessPoint::ACCESS_POINT_USER_MANAGER:
+ case AccessPoint::ACCESS_POINT_UNKNOWN:
+ NOTREACHED() << "Signin_Impression_From* user actions"
+ << " are not recorded for access_point "
+ << static_cast<int>(access_point);
+ break;
+ case AccessPoint::ACCESS_POINT_MAX:
+ NOTREACHED();
break;
- case signin_metrics::AccessPoint::ACCESS_POINT_MAX:
+ }
+}
+
+void RecordSigninImpressionWithAccountUserActionForAccessPoint(
+ AccessPoint access_point,
+ bool with_account) {
+ switch (access_point) {
+ case AccessPoint::ACCESS_POINT_SETTINGS:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromSettings"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromSettings"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromExtensionInstallBubble"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromExtensionInstallBubble"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromBookmarkBubble"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromBookmarkBubble"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromBookmarkManager"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromBookmarkManager"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromAvatarBubbleSignin"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromAvatarBubbleSignin"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_RECENT_TABS:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromRecentTabs"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromRecentTabs"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromPasswordBubble"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromPasswordBubble"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_TAB_SWITCHER:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromTabSwitcher"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromTabSwitcher"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS:
+ if (with_account) {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithAccount_FromNTPContentSuggestions"));
+ } else {
+ base::RecordAction(base::UserMetricsAction(
+ "Signin_ImpressionWithNoAccount_FromNTPContentSuggestions"));
+ }
+ break;
+ case AccessPoint::ACCESS_POINT_START_PAGE:
+ case AccessPoint::ACCESS_POINT_NTP_LINK:
+ case AccessPoint::ACCESS_POINT_MENU:
+ case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
+ case AccessPoint::ACCESS_POINT_EXTENSIONS:
+ case AccessPoint::ACCESS_POINT_APPS_PAGE_LINK:
+ case AccessPoint::ACCESS_POINT_USER_MANAGER:
+ case AccessPoint::ACCESS_POINT_DEVICES_PAGE:
+ case AccessPoint::ACCESS_POINT_CLOUD_PRINT:
+ case AccessPoint::ACCESS_POINT_CONTENT_AREA:
+ case AccessPoint::ACCESS_POINT_SIGNIN_PROMO:
+ case AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN:
+ case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
+ case AccessPoint::ACCESS_POINT_UNKNOWN:
+ case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ NOTREACHED() << "Signin_Impression{With|WithNo}Account_From* user actions"
+ << " are not recorded for access_point "
+ << static_cast<int>(access_point)
+ << " as it does not support a personalized sign-in promo.";
+ break;
+ case AccessPoint::ACCESS_POINT_MAX:
NOTREACHED();
break;
}
diff --git a/chromium/components/signin/core/browser/signin_metrics.h b/chromium/components/signin/core/browser/signin_metrics.h
index f288eba4258..132b33b0428 100644
--- a/chromium/components/signin/core/browser/signin_metrics.h
+++ b/chromium/components/signin/core/browser/signin_metrics.h
@@ -301,11 +301,7 @@ enum class ReportingType { PERIODIC, ON_CHANGE };
// Histograms
// -----------------------------------------------------------------------------
-// Tracks the access point of sign in on desktop.
-void LogSigninAccessPointStarted(AccessPoint access_point);
-void LogSigninAccessPointCompleted(AccessPoint access_point);
-
-// Tracks the access point of sign in on iOS.
+// Tracks the access point of sign in.
void LogSigninAccessPointStarted(AccessPoint access_point,
PromoAction promo_action);
void LogSigninAccessPointCompleted(AccessPoint access_point,
@@ -358,7 +354,7 @@ void LogExternalCcResultFetches(
const base::TimeDelta& time_to_check_connections);
// Track when the current authentication error changed.
-void LogAuthError(GoogleServiceAuthError::State auth_error);
+void LogAuthError(const GoogleServiceAuthError& auth_error);
void LogSigninConfirmHistogramValue(ConfirmationUsage action);
@@ -401,8 +397,16 @@ void LogIsShared(const bool is_shared, const ReportingType type);
// -----------------------------------------------------------------------------
// Records corresponding sign in user action for an access point.
-void RecordSigninUserActionForAccessPoint(
- signin_metrics::AccessPoint access_point);
+void RecordSigninUserActionForAccessPoint(AccessPoint access_point,
+ PromoAction promo_action);
+
+// Records |Signin_ImpressionWithAccount_From*| user action.
+void RecordSigninImpressionUserActionForAccessPoint(AccessPoint access_point);
+
+// Records |Signin_Impression{With|No}Account_From*| user action.
+void RecordSigninImpressionWithAccountUserActionForAccessPoint(
+ AccessPoint access_point,
+ bool with_account);
} // namespace signin_metrics
diff --git a/chromium/components/signin/core/browser/signin_metrics_unittest.cc b/chromium/components/signin/core/browser/signin_metrics_unittest.cc
new file mode 100644
index 00000000000..5361634a935
--- /dev/null
+++ b/chromium/components/signin/core/browser/signin_metrics_unittest.cc
@@ -0,0 +1,190 @@
+// Copyright 2018 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/signin/core/browser/signin_metrics.h"
+
+#include <string>
+#include <vector>
+
+#include "base/test/user_action_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace signin_metrics {
+
+namespace {
+
+const AccessPoint kAccessPointsThatSupportImpression[] = {
+ AccessPoint::ACCESS_POINT_START_PAGE,
+ AccessPoint::ACCESS_POINT_NTP_LINK,
+ AccessPoint::ACCESS_POINT_MENU,
+ AccessPoint::ACCESS_POINT_SETTINGS,
+ AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE,
+ AccessPoint::ACCESS_POINT_APPS_PAGE_LINK,
+ AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE,
+ AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER,
+ AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN,
+ AccessPoint::ACCESS_POINT_DEVICES_PAGE,
+ AccessPoint::ACCESS_POINT_CLOUD_PRINT,
+ AccessPoint::ACCESS_POINT_SIGNIN_PROMO,
+ AccessPoint::ACCESS_POINT_RECENT_TABS,
+ AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE,
+ AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN,
+ AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS,
+ AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR,
+ AccessPoint::ACCESS_POINT_TAB_SWITCHER};
+
+const AccessPoint kAccessPointsThatSupportPersonalizedPromos[] = {
+ AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER,
+ AccessPoint::ACCESS_POINT_RECENT_TABS,
+ AccessPoint::ACCESS_POINT_SETTINGS,
+ AccessPoint::ACCESS_POINT_TAB_SWITCHER,
+ AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE,
+ AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN,
+ AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE,
+ AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE,
+ AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS};
+
+class SigninMetricsTest : public ::testing::Test {
+ public:
+ static std::string GetAccessPointDescription(AccessPoint access_point) {
+ switch (access_point) {
+ case AccessPoint::ACCESS_POINT_START_PAGE:
+ return "StartPage";
+ case AccessPoint::ACCESS_POINT_NTP_LINK:
+ return "NTP";
+ case AccessPoint::ACCESS_POINT_MENU:
+ return "Menu";
+ case AccessPoint::ACCESS_POINT_SETTINGS:
+ return "Settings";
+ case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
+ return "SupervisedUser";
+ case AccessPoint::ACCESS_POINT_EXTENSION_INSTALL_BUBBLE:
+ return "ExtensionInstallBubble";
+ case AccessPoint::ACCESS_POINT_EXTENSIONS:
+ return "Extensions";
+ case AccessPoint::ACCESS_POINT_APPS_PAGE_LINK:
+ return "AppsPageLink";
+ case AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE:
+ return "BookmarkBubble";
+ case AccessPoint::ACCESS_POINT_BOOKMARK_MANAGER:
+ return "BookmarkManager";
+ case AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN:
+ return "AvatarBubbleSignin";
+ case AccessPoint::ACCESS_POINT_USER_MANAGER:
+ return "UserManager";
+ case AccessPoint::ACCESS_POINT_DEVICES_PAGE:
+ return "DevicesPage";
+ case AccessPoint::ACCESS_POINT_CLOUD_PRINT:
+ return "CloudPrint";
+ case AccessPoint::ACCESS_POINT_CONTENT_AREA:
+ return "ContentArea";
+ case AccessPoint::ACCESS_POINT_SIGNIN_PROMO:
+ return "SigninPromo";
+ case AccessPoint::ACCESS_POINT_RECENT_TABS:
+ return "RecentTabs";
+ case AccessPoint::ACCESS_POINT_UNKNOWN:
+ return "UnknownAccessPoint";
+ case AccessPoint::ACCESS_POINT_PASSWORD_BUBBLE:
+ return "PasswordBubble";
+ case AccessPoint::ACCESS_POINT_AUTOFILL_DROPDOWN:
+ return "AutofillDropdown";
+ case AccessPoint::ACCESS_POINT_NTP_CONTENT_SUGGESTIONS:
+ return "NTPContentSuggestions";
+ case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
+ return "ReSigninInfobar";
+ case AccessPoint::ACCESS_POINT_TAB_SWITCHER:
+ return "TabSwitcher";
+ case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+ return "ForceSigninWarning";
+ case AccessPoint::ACCESS_POINT_MAX:
+ NOTREACHED();
+ return "";
+ }
+ NOTREACHED();
+ return "";
+ }
+
+ static std::vector<AccessPoint> GetAllAccessPoints() {
+ std::vector<AccessPoint> access_points;
+ for (int ap = 0; ap < static_cast<int>(AccessPoint::ACCESS_POINT_MAX);
+ ++ap) {
+ access_points.push_back(static_cast<AccessPoint>(ap));
+ }
+ return access_points;
+ }
+};
+
+TEST_F(SigninMetricsTest, RecordSigninUserActionForAccessPoint) {
+ for (const AccessPoint& ap : GetAllAccessPoints()) {
+ base::UserActionTester user_action_tester;
+ RecordSigninUserActionForAccessPoint(
+ ap, signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO);
+ EXPECT_EQ(1, user_action_tester.GetActionCount(
+ "Signin_Signin_From" + GetAccessPointDescription(ap)));
+ }
+}
+
+TEST_F(SigninMetricsTest, RecordSigninUserActionWithPromoAction) {
+ for (const AccessPoint& ap : kAccessPointsThatSupportPersonalizedPromos) {
+ {
+ // PROMO_ACTION_WITH_DEFAULT promo action
+ base::UserActionTester user_action_tester;
+ RecordSigninUserActionForAccessPoint(
+ ap, signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT);
+ EXPECT_EQ(
+ 1, user_action_tester.GetActionCount("Signin_SigninWithDefault_From" +
+ GetAccessPointDescription(ap)));
+ }
+ {
+ // PROMO_ACTION_NOT_DEFAULT promo action
+ base::UserActionTester user_action_tester;
+ RecordSigninUserActionForAccessPoint(
+ ap, signin_metrics::PromoAction::PROMO_ACTION_NOT_DEFAULT);
+ EXPECT_EQ(
+ 1, user_action_tester.GetActionCount("Signin_SigninNotDefault_From" +
+ GetAccessPointDescription(ap)));
+ }
+ {
+ // PROMO_ACTION_NEW_ACCOUNT promo action
+ base::UserActionTester user_action_tester;
+ RecordSigninUserActionForAccessPoint(
+ ap, signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT);
+ EXPECT_EQ(
+ 1, user_action_tester.GetActionCount("Signin_SigninNewAccount_From" +
+ GetAccessPointDescription(ap)));
+ }
+ }
+}
+
+TEST_F(SigninMetricsTest, RecordSigninImpressionUserAction) {
+ for (const AccessPoint& ap : kAccessPointsThatSupportImpression) {
+ base::UserActionTester user_action_tester;
+ RecordSigninImpressionUserActionForAccessPoint(ap);
+ EXPECT_EQ(1, user_action_tester.GetActionCount(
+ "Signin_Impression_From" + GetAccessPointDescription(ap)));
+ }
+}
+
+TEST_F(SigninMetricsTest, RecordSigninImpressionWithAccountUserAction) {
+ for (const AccessPoint& ap : kAccessPointsThatSupportPersonalizedPromos) {
+ base::UserActionTester user_action_tester;
+ RecordSigninImpressionWithAccountUserActionForAccessPoint(ap, true);
+ EXPECT_EQ(1, user_action_tester.GetActionCount(
+ "Signin_ImpressionWithAccount_From" +
+ GetAccessPointDescription(ap)));
+ }
+}
+
+TEST_F(SigninMetricsTest, RecordSigninImpressionWithNoAccountUserAction) {
+ for (const AccessPoint& ap : kAccessPointsThatSupportPersonalizedPromos) {
+ base::UserActionTester user_action_tester;
+ RecordSigninImpressionWithAccountUserActionForAccessPoint(ap, false);
+ EXPECT_EQ(1, user_action_tester.GetActionCount(
+ "Signin_ImpressionWithNoAccount_From" +
+ GetAccessPointDescription(ap)));
+ }
+}
+
+} // namespace
+} // namespace signin_metrics
diff --git a/chromium/components/signin/core/browser/signin_switches.h b/chromium/components/signin/core/browser/signin_switches.h
index 291c6023968..71cf2a59dca 100644
--- a/chromium/components/signin/core/browser/signin_switches.h
+++ b/chromium/components/signin/core/browser/signin_switches.h
@@ -5,7 +5,7 @@
#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_SIGNIN_SWITCHES_H_
#define COMPONENTS_SIGNIN_CORE_BROWSER_SIGNIN_SWITCHES_H_
-#include "components/signin/core/browser/signin_features.h"
+#include "components/signin/core/browser/signin_buildflags.h"
namespace switches {
diff --git a/chromium/components/signin/core/browser/test_signin_client.cc b/chromium/components/signin/core/browser/test_signin_client.cc
index 63a7e044708..8eb66ddba2f 100644
--- a/chromium/components/signin/core/browser/test_signin_client.cc
+++ b/chromium/components/signin/core/browser/test_signin_client.cc
@@ -14,7 +14,9 @@
#include "testing/gtest/include/gtest/gtest.h"
TestSigninClient::TestSigninClient(PrefService* pref_service)
- : pref_service_(pref_service), are_signin_cookies_allowed_(true) {}
+ : pref_service_(pref_service),
+ are_signin_cookies_allowed_(true),
+ network_calls_delayed_(false) {}
TestSigninClient::~TestSigninClient() {}
@@ -79,6 +81,16 @@ TestSigninClient::AddCookieChangeCallback(const GURL& url,
return std::make_unique<SigninClient::CookieChangeSubscription>();
}
+void TestSigninClient::SetNetworkCallsDelayed(bool value) {
+ network_calls_delayed_ = value;
+
+ if (!network_calls_delayed_) {
+ for (base::OnceClosure& call : delayed_network_calls_)
+ std::move(call).Run();
+ delayed_network_calls_.clear();
+ }
+}
+
bool TestSigninClient::IsFirstRun() const {
return false;
}
@@ -100,7 +112,11 @@ void TestSigninClient::RemoveContentSettingsObserver(
}
void TestSigninClient::DelayNetworkCall(const base::Closure& callback) {
- callback.Run();
+ if (network_calls_delayed_) {
+ delayed_network_calls_.push_back(callback);
+ } else {
+ callback.Run();
+ }
}
std::unique_ptr<GaiaAuthFetcher> TestSigninClient::CreateGaiaAuthFetcher(
diff --git a/chromium/components/signin/core/browser/test_signin_client.h b/chromium/components/signin/core/browser/test_signin_client.h
index b3f416b509a..3aeb831f664 100644
--- a/chromium/components/signin/core/browser/test_signin_client.h
+++ b/chromium/components/signin/core/browser/test_signin_client.h
@@ -6,7 +6,10 @@
#define COMPONENTS_SIGNIN_CORE_BROWSER_TEST_SIGNIN_CLIENT_H_
#include <memory>
+#include <string>
+#include <vector>
+#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
@@ -78,6 +81,12 @@ class TestSigninClient : public SigninClient {
are_signin_cookies_allowed_ = value;
}
+ // When |value| is true, network calls posted through DelayNetworkCall() are
+ // delayed indefinitely.
+ // When |value| is false, all pending calls are unblocked, and new calls are
+ // executed immediately.
+ void SetNetworkCallsDelayed(bool value);
+
// SigninClient overrides:
bool IsFirstRun() const override;
base::Time GetInstallDate() override;
@@ -102,6 +111,8 @@ class TestSigninClient : public SigninClient {
scoped_refptr<TokenWebData> database_;
PrefService* pref_service_;
bool are_signin_cookies_allowed_;
+ bool network_calls_delayed_;
+ std::vector<base::OnceClosure> delayed_network_calls_;
// Pointer to be filled by PostSignedIn.
std::string signed_in_password_;
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
index d437a8b44a7..79ae397f64a 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
@@ -35,7 +35,8 @@ class ProfileOAuth2TokenServiceIOSDelegate : public OAuth2TokenServiceDelegate {
void Shutdown() override;
bool RefreshTokenIsAvailable(const std::string& account_id) const override;
- bool RefreshTokenHasError(const std::string& account_id) const override;
+ GoogleServiceAuthError GetAuthError(
+ const std::string& account_id) const override;
void UpdateAuthError(const std::string& account_id,
const GoogleServiceAuthError& error) override;
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
index 5e93fc97e51..a34d4127db6 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
@@ -51,8 +51,9 @@ GoogleServiceAuthError GetGoogleServiceAuthErrorFromNSError(
return GoogleServiceAuthError(
GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE);
case kAuthenticationErrorCategoryAuthorizationErrors:
- return GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+ return GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_SERVER);
case kAuthenticationErrorCategoryAuthorizationForbiddenErrors:
// HTTP_FORBIDDEN (403) is treated as temporary error, because it may be
// '403 Rate Limit Exceeded.' (for more details, see
@@ -163,10 +164,8 @@ ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::~AccountStatus() {
void ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::SetLastAuthError(
const GoogleServiceAuthError& error) {
- if (error.state() != last_auth_error_.state()) {
last_auth_error_ = error;
signin_error_controller_->AuthStatusChanged();
- }
}
std::string ProfileOAuth2TokenServiceIOSDelegate::AccountStatus::GetAccountId()
@@ -324,12 +323,11 @@ bool ProfileOAuth2TokenServiceIOSDelegate::RefreshTokenIsAvailable(
return accounts_.count(account_id) > 0;
}
-bool ProfileOAuth2TokenServiceIOSDelegate::RefreshTokenHasError(
+GoogleServiceAuthError ProfileOAuth2TokenServiceIOSDelegate::GetAuthError(
const std::string& account_id) const {
- DCHECK(thread_checker_.CalledOnValidThread());
auto it = accounts_.find(account_id);
- // TODO(rogerta): should we distinguish between transient and persistent?
- return it == accounts_.end() ? false : IsError(it->second->GetAuthStatus());
+ return (it == accounts_.end()) ? GoogleServiceAuthError::AuthErrorNone()
+ : it->second->GetAuthStatus();
}
void ProfileOAuth2TokenServiceIOSDelegate::UpdateAuthError(
@@ -340,16 +338,19 @@ void ProfileOAuth2TokenServiceIOSDelegate::UpdateAuthError(
// Do not report connection errors as these are not actually auth errors.
// We also want to avoid masking a "real" auth error just because we
// subsequently get a transient network error.
- if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
- error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
+ if (error.IsTransientError())
return;
- }
if (accounts_.count(account_id) == 0) {
// Nothing to update as the account has already been removed.
return;
}
- accounts_[account_id]->SetLastAuthError(error);
+
+ AccountStatus* status = accounts_[account_id].get();
+ if (error.state() != status->GetAuthStatus().state()) {
+ status->SetLastAuthError(error);
+ FireAuthErrorChanged(account_id, error);
+ }
}
// Clear the authentication error state and notify all observers that a new
@@ -374,6 +375,7 @@ void ProfileOAuth2TokenServiceIOSDelegate::AddOrUpdateAccount(
if (!account_present) {
accounts_[account_id].reset(
new AccountStatus(signin_error_controller_, account_id));
+ FireAuthErrorChanged(account_id, accounts_[account_id]->GetAuthStatus());
}
UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone());
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
index b6a26c0ee4a..9131b9bb76b 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
@@ -43,6 +43,8 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
tokens_loaded_count_(0),
access_token_success_(0),
access_token_failure_(0),
+ error_changed_count_(0),
+ auth_error_changed_count_(0),
last_access_token_error_(GoogleServiceAuthError::NONE) {}
void SetUp() override {
@@ -93,7 +95,12 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
++token_revoked_count_;
}
void OnRefreshTokensLoaded() override { ++tokens_loaded_count_; }
+ void OnAuthErrorChanged(const std::string& account_id,
+ const GoogleServiceAuthError& error) override {
+ ++auth_error_changed_count_;
+ }
+ // SigninErrorController::Observer implementation.
void OnErrorChanged() override { ++error_changed_count_; }
void ResetObserverCounts() {
@@ -103,6 +110,7 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
token_available_count_ = 0;
access_token_failure_ = 0;
error_changed_count_ = 0;
+ auth_error_changed_count_ = 0;
}
std::string GetAccountId(const ProviderAccount& provider_account) {
@@ -126,6 +134,7 @@ class ProfileOAuth2TokenServiceIOSDelegateTest
int access_token_success_;
int access_token_failure_;
int error_changed_count_;
+ int auth_error_changed_count_;
GoogleServiceAuthError last_access_token_error_;
};
@@ -298,10 +307,32 @@ TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest,
ResetObserverCounts();
GoogleServiceAuthError error(GoogleServiceAuthError::SERVICE_ERROR);
oauth2_delegate_->UpdateAuthError(GetAccountId(account1), error);
+ EXPECT_EQ(error, oauth2_delegate_->GetAuthError("gaia_1"));
+ EXPECT_EQ(1, auth_error_changed_count_);
EXPECT_EQ(1, error_changed_count_);
oauth2_delegate_->RevokeAllCredentials();
ResetObserverCounts();
oauth2_delegate_->UpdateAuthError(GetAccountId(account1), error);
+ EXPECT_EQ(0, auth_error_changed_count_);
EXPECT_EQ(0, error_changed_count_);
}
+
+TEST_F(ProfileOAuth2TokenServiceIOSDelegateTest, GetAuthError) {
+ // Accounts have no error by default.
+ ProviderAccount account1 = fake_provider_->AddAccount("gaia_1", "email_1@x");
+ oauth2_delegate_->ReloadCredentials(GetAccountId(account1));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_delegate_->GetAuthError("gaia_1"));
+ // Update the error.
+ GoogleServiceAuthError error =
+ GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_SERVER);
+ oauth2_delegate_->UpdateAuthError("gaia_1", error);
+ EXPECT_EQ(error, oauth2_delegate_->GetAuthError("gaia_1"));
+ // Unknown account has no error.
+ EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
+ oauth2_delegate_->GetAuthError("gaia_2"));
+}