Skip to content

Commit

Permalink
[4/4] Account Capabilities Fetcher
Browse files Browse the repository at this point in the history
This CL adds an AccountCapabilitiesFetcher class which fetches an
access token + calls into GaiaOAuthClient to send a request to the
Account Capabilities API for a specific account.

AccountFetcherService schedules an account capabilities fetch whenever a
new refresh token is available for an account + periodically refreshes
data every 24 hours. This functionaliy is currently put behind the
MinorModeSupport feature flag.

Finally, AccountTrackerService updates AccountInfo with the newly
fetched capabilities and persist them to prefs.

Bug: 1213071
Change-Id: Ic2ad92c3f43fa13a15ef38d8e5ea04dc18dda469
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2940072
Reviewed-by: Mihai Sardarescu <msarda@chromium.org>
Commit-Queue: Alex Ilin <alexilin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#892578}
  • Loading branch information
Alex Ilin authored and Chromium LUCI CQ committed Jun 15, 2021
1 parent 0da316d commit d731c61
Show file tree
Hide file tree
Showing 15 changed files with 621 additions and 1 deletion.
4 changes: 4 additions & 0 deletions components/signin/internal/identity_manager/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import("//components/signin/features.gni")
# (//components/signin/public/identity_manager/identity_manager.*).
source_set("identity_manager") {
sources = [
"account_capabilities_constants.cc",
"account_capabilities_constants.h",
"account_capabilities_fetcher.cc",
"account_capabilities_fetcher.h",
"account_fetcher_service.cc",
"account_fetcher_service.h",
"account_info_fetcher.cc",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2021 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/internal/identity_manager/account_capabilities_constants.h"

const char kCanOfferExtendedChromeSyncPromosCapabilityName[] =
"accountcapabilities/gi2tklldmfya";

const char kCanOfferExtendedChromeSyncPromosCapabilityPrefsPath[] =
"accountcapabilities.can_offer_extended_chrome_sync_promos";
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2021 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_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_CONSTANTS_H_
#define COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_CONSTANTS_H_

extern const char kCanOfferExtendedChromeSyncPromosCapabilityName[];
extern const char kCanOfferExtendedChromeSyncPromosCapabilityPrefsPath[];

#endif // COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_CONSTANTS_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2021 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/internal/identity_manager/account_capabilities_fetcher.h"

#include "base/trace_event/trace_event.h"
#include "components/signin/internal/identity_manager/account_capabilities_constants.h"
#include "components/signin/internal/identity_manager/account_fetcher_service.h"
#include "components/signin/internal/identity_manager/account_info_util.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_consumer.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"

AccountCapabilitiesFetcher::AccountCapabilitiesFetcher(
ProfileOAuth2TokenService* token_service,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AccountFetcherService* service,
const CoreAccountId& account_id)
: OAuth2AccessTokenManager::Consumer("account_capabilities_fetcher"),
token_service_(token_service),
url_loader_factory_(std::move(url_loader_factory)),
service_(service),
account_id_(account_id) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("AccountFetcherService",
"AccountCapabilitiesFetcher", this,
"account_id", account_id.ToString());
}

AccountCapabilitiesFetcher::~AccountCapabilitiesFetcher() {
TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService",
"AccountCapabilitiesFetcher", this);
}

void AccountCapabilitiesFetcher::Start() {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("AccountFetcherService", "GetAccessToken",
this);
OAuth2AccessTokenManager::ScopeSet scopes;
scopes.insert(GaiaConstants::kAccountCapabilitiesOAuth2Scope);
login_token_request_ =
token_service_->StartRequest(account_id_, scopes, this);
}

void AccountCapabilitiesFetcher::OnGetTokenSuccess(
const OAuth2AccessTokenManager::Request* request,
const OAuth2AccessTokenConsumer::TokenResponse& token_response) {
TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService", "GetAccessToken",
this);
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("AccountFetcherService",
"GetAccountCapabilities", this);
DCHECK_EQ(request, login_token_request_.get());
login_token_request_.reset();

gaia_oauth_client_ =
std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory_);
const int kMaxRetries = 3;
gaia_oauth_client_->GetAccountCapabilities(
token_response.access_token,
{kCanOfferExtendedChromeSyncPromosCapabilityName}, kMaxRetries, this);
}

void AccountCapabilitiesFetcher::OnGetTokenFailure(
const OAuth2AccessTokenManager::Request* request,
const GoogleServiceAuthError& error) {
TRACE_EVENT_NESTABLE_ASYNC_END1("AccountFetcherService", "GetAccessToken",
this, "error", error.ToString());
VLOG(1) << "OnGetTokenFailure: " << error.ToString();
DCHECK_EQ(request, login_token_request_.get());
login_token_request_.reset();
service_->OnAccountCapabilitiesFetchFailure(account_id_);
}

void AccountCapabilitiesFetcher::OnGetAccountCapabilitiesResponse(
std::unique_ptr<base::Value> account_capabilities) {
TRACE_EVENT_NESTABLE_ASYNC_END0("AccountFetcherService",
"GetAccountCapabilities", this);
absl::optional<AccountCapabilities> parsed_capabilities =
AccountCapabilitiesFromValue(*account_capabilities);
if (!parsed_capabilities) {
VLOG(1) << "Failed to parse account capabilities for " << account_id_
<< ". Response body: " << account_capabilities->DebugString();
service_->OnAccountCapabilitiesFetchFailure(account_id_);
return;
}

service_->OnAccountCapabilitiesFetchSuccess(account_id_,
parsed_capabilities.value());
}

void AccountCapabilitiesFetcher::OnOAuthError() {
TRACE_EVENT_NESTABLE_ASYNC_END1("AccountFetcherService",
"GetAccountCapabilities", this, "error",
"OAuthError");
VLOG(1) << "OnOAuthError";
service_->OnAccountCapabilitiesFetchFailure(account_id_);
}

void AccountCapabilitiesFetcher::OnNetworkError(int response_code) {
TRACE_EVENT_NESTABLE_ASYNC_END2(
"AccountFetcherService", "GetAccountCapabilities", this, "error",
"NetworkError", "response_code", response_code);
VLOG(1) << "OnNetworkError " << response_code;
service_->OnAccountCapabilitiesFetchFailure(account_id_);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2021 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_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_H_
#define COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_H_

#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "google_apis/gaia/core_account_id.h"
#include "google_apis/gaia/gaia_oauth_client.h"
#include "google_apis/gaia/oauth2_access_token_manager.h"

namespace network {
class SharedURLLoaderFactory;
}

class AccountFetcherService;
class ProfileOAuth2TokenService;
class GoogleServiceAuthError;

class AccountCapabilitiesFetcher : public OAuth2AccessTokenManager::Consumer,
public gaia::GaiaOAuthClient::Delegate {
public:
AccountCapabilitiesFetcher(
ProfileOAuth2TokenService* token_service,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AccountFetcherService* service,
const CoreAccountId& account_id);
~AccountCapabilitiesFetcher() override;

AccountCapabilitiesFetcher(const AccountCapabilitiesFetcher&) = delete;
AccountCapabilitiesFetcher& operator=(const AccountCapabilitiesFetcher&) =
delete;

// Start fetching account capabilities.
void Start();

// OAuth2AccessTokenManager::Consumer:
void OnGetTokenSuccess(
const OAuth2AccessTokenManager::Request* request,
const OAuth2AccessTokenConsumer::TokenResponse& token_response) override;
void OnGetTokenFailure(const OAuth2AccessTokenManager::Request* request,
const GoogleServiceAuthError& error) override;

// gaia::GaiaOAuthClient::Delegate:
void OnGetAccountCapabilitiesResponse(
std::unique_ptr<base::Value> account_capabilities) override;
void OnOAuthError() override;
void OnNetworkError(int response_code) override;

private:
ProfileOAuth2TokenService* token_service_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
AccountFetcherService* service_;
const CoreAccountId account_id_;

std::unique_ptr<OAuth2AccessTokenManager::Request> login_token_request_;
std::unique_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_;
};

#endif // COMPONENTS_SIGNIN_INTERNAL_IDENTITY_MANAGER_ACCOUNT_CAPABILITIES_FETCHER_H_
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,25 @@

#include "base/bind.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_functions.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/image_fetcher/core/image_decoder.h"
#include "components/image_fetcher/core/image_fetcher_impl.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/signin/internal/identity_manager/account_capabilities_fetcher.h"
#include "components/signin/internal/identity_manager/account_info_fetcher.h"
#include "components/signin/internal/identity_manager/account_tracker_service.h"
#include "components/signin/internal/identity_manager/profile_oauth2_token_service.h"
#include "components/signin/public/base/avatar_icon_util.h"
#include "components/signin/public/base/signin_client.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/signin/public/identity_manager/account_capabilities.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"

Expand Down Expand Up @@ -99,6 +104,10 @@ bool AccountFetcherService::IsAllUserInfoFetched() const {
return user_info_requests_.empty();
}

bool AccountFetcherService::AreAllAccountCapabilitiesFetched() const {
return account_capabilities_requests_.empty();
}

void AccountFetcherService::ForceRefreshOfAccountInfo(
const CoreAccountId& account_id) {
DCHECK(network_fetches_enabled_);
Expand Down Expand Up @@ -127,6 +136,11 @@ void AccountFetcherService::EnableAccountRemovalForTest() {
enable_account_removal_for_test_ = true;
}

void AccountFetcherService::EnableAccountCapabilitiesFetcherForTest(
bool enabled) {
enable_account_capabilities_fetcher_for_test_ = enabled;
}

void AccountFetcherService::RefreshAllAccountInfo(bool only_fetch_if_invalid) {
for (const auto& account : token_service_->GetAccounts()) {
RefreshAccountInfo(account, only_fetch_if_invalid);
Expand Down Expand Up @@ -212,13 +226,44 @@ void AccountFetcherService::SetIsChildAccount(const CoreAccountId& account_id,
}
#endif

bool AccountFetcherService::IsAccountCapabilitiesFetcherEnabled() {
if (enable_account_capabilities_fetcher_for_test_)
return true;

#if BUILDFLAG(IS_CHROMEOS_ASH)
return base::FeatureList::IsEnabled(switches::kMinorModeSupport);
#endif
return false;
}

void AccountFetcherService::StartFetchingAccountCapabilities(
const CoreAccountId& account_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(network_fetches_enabled_);

std::unique_ptr<AccountCapabilitiesFetcher>& request =
account_capabilities_requests_[account_id];
if (!request) {
request = std::make_unique<AccountCapabilitiesFetcher>(
token_service_, signin_client_->GetURLLoaderFactory(), this,
account_id);
request->Start();
}
}

void AccountFetcherService::RefreshAccountInfo(const CoreAccountId& account_id,
bool only_fetch_if_invalid) {
DCHECK(network_fetches_enabled_);
account_tracker_service_->StartTrackingAccount(account_id);
const AccountInfo& info =
account_tracker_service_->GetAccountInfo(account_id);

if ((!only_fetch_if_invalid ||
!info.capabilities.AreAllCapabilitiesKnown()) &&
IsAccountCapabilitiesFetcherEnabled()) {
StartFetchingAccountCapabilities(account_id);
}

// |only_fetch_if_invalid| is false when the service is due for a timed
// update.
if (!only_fetch_if_invalid || !info.IsValid()) {
Expand Down Expand Up @@ -323,6 +368,21 @@ void AccountFetcherService::OnUserInfoFetchFailure(
user_info_requests_.erase(account_id);
}

void AccountFetcherService::OnAccountCapabilitiesFetchSuccess(
const CoreAccountId& account_id,
const AccountCapabilities& account_capabilities) {
account_tracker_service_->SetAccountCapabilities(account_id,
account_capabilities);
account_capabilities_requests_.erase(account_id);
}

void AccountFetcherService::OnAccountCapabilitiesFetchFailure(
const CoreAccountId& account_id) {
VLOG(1) << "Failed to get AccountCapabilities for " << account_id;
// |account_id| is owned by the request. Cannot be used after this line.
account_capabilities_requests_.erase(account_id);
}

void AccountFetcherService::OnRefreshTokenAvailable(
const CoreAccountId& account_id) {
TRACE_EVENT1("AccountFetcherService",
Expand Down Expand Up @@ -359,6 +419,7 @@ void AccountFetcherService::OnRefreshTokenRevoked(
}

user_info_requests_.erase(account_id);
account_capabilities_requests_.erase(account_id);
#if defined(OS_ANDROID)
UpdateChildInfo();
#endif
Expand Down

0 comments on commit d731c61

Please sign in to comment.