From 2d7f8e78a441f9fda8c5353b3127ea726b055376 Mon Sep 17 00:00:00 2001 From: knn Date: Tue, 28 Jul 2015 14:53:10 -0700 Subject: [PATCH] Add an Android specific ChildAccountInfoFetcher that talks to the AccountManager. Based on http://crrev.com/1224643007 BUG=508054 Review URL: https://codereview.chromium.org/1231653007 Cr-Commit-Position: refs/heads/master@{#340774} --- chrome/android/BUILD.gn | 5 +- .../browser/android/chrome_jni_registrar.cc | 10 +- chrome/chrome.gyp | 1 + components/components_tests.gyp | 1 + components/signin.gypi | 44 +++++ components/signin/core/browser/BUILD.gn | 14 ++ components/signin/core/browser/DEPS | 1 + .../core/browser/account_fetcher_service.cc | 11 +- .../core/browser/account_fetcher_service.h | 3 +- .../signin/core/browser/android/BUILD.gn | 23 +++ .../android/component_jni_registrar.cc | 25 +++ .../browser/android/component_jni_registrar.h | 18 ++ .../signin/core/browser/android/java/DEPS | 3 + .../signin/ChildAccountInfoFetcher.java | 67 +++++++ .../browser/child_account_info_fetcher.cc | 178 ++---------------- .../core/browser/child_account_info_fetcher.h | 77 ++------ .../child_account_info_fetcher_android.cc | 45 +++++ .../child_account_info_fetcher_android.h | 28 +++ .../child_account_info_fetcher_impl.cc | 173 +++++++++++++++++ .../browser/child_account_info_fetcher_impl.h | 73 +++++++ components/test/DEPS | 1 + components/test/run_all_unittests.cc | 2 + 22 files changed, 573 insertions(+), 230 deletions(-) create mode 100644 components/signin/core/browser/android/BUILD.gn create mode 100644 components/signin/core/browser/android/component_jni_registrar.cc create mode 100644 components/signin/core/browser/android/component_jni_registrar.h create mode 100644 components/signin/core/browser/android/java/DEPS create mode 100644 components/signin/core/browser/android/java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java create mode 100644 components/signin/core/browser/child_account_info_fetcher_android.cc create mode 100644 components/signin/core/browser/child_account_info_fetcher_android.h create mode 100644 components/signin/core/browser/child_account_info_fetcher_impl.cc create mode 100644 components/signin/core/browser/child_account_info_fetcher_impl.h diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index d96b49bf3cbd88..a843951f3cef53 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn @@ -126,10 +126,11 @@ android_library("chrome_java") { "//components/gcm_driver/android:gcm_driver_java", "//components/invalidation/impl:java", "//components/navigation_interception/android:navigation_interception_java", - "//components/safe_json/android:safe_json_java", - "//components/service_tab_launcher:service_tab_launcher_java", "//components/policy/android:policy_java", "//components/precache/android:precache_java", + "//components/safe_json/android:safe_json_java", + "//components/service_tab_launcher:service_tab_launcher_java", + "//components/signin/core/browser/android:java", "//components/variations/android:variations_java", "//components/web_contents_delegate_android:web_contents_delegate_android_java", "//content/public/android:content_java", diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index 1d1fc11509a0de..daf507a312ab87 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc @@ -134,6 +134,7 @@ #include "components/policy/core/browser/android/component_jni_registrar.h" #include "components/safe_json/android/component_jni_registrar.h" #include "components/service_tab_launcher/component_jni_registrar.h" +#include "components/signin/core/browser/android/component_jni_registrar.h" #include "components/variations/android/component_jni_registrar.h" #include "components/web_contents_delegate_android/component_jni_registrar.h" @@ -156,6 +157,7 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = { navigation_interception::RegisterNavigationInterceptionJni}, {"Policy", policy::android::RegisterPolicy}, {"SafeJson", safe_json::android::RegisterSafeJsonJni}, + {"Signin", signin::android::RegisterSigninJni}, {"WebContentsDelegateAndroid", web_contents_delegate_android::RegisterWebContentsDelegateAndroidJni}, // Register JNI for chrome classes. @@ -174,9 +176,8 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = { RegisterAutofillDialogControllerAndroid}, {"AutofillDialogResult", autofill::AutofillDialogResult::RegisterAutofillDialogResult}, - {"AutofillKeyboardAccessory", - autofill::AutofillKeyboardAccessoryView:: - RegisterAutofillKeyboardAccessoryView}, + {"AutofillKeyboardAccessory", autofill::AutofillKeyboardAccessoryView:: + RegisterAutofillKeyboardAccessoryView}, {"AutofillLoggerAndroid", autofill::AutofillLoggerAndroid::Register}, {"AutofillPopup", autofill::AutofillPopupViewAndroid::RegisterAutofillPopupViewAndroid}, @@ -252,8 +253,7 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = { NotificationUIManagerAndroid::RegisterNotificationUIManager}, {"OAuth2TokenServiceDelegateAndroid", OAuth2TokenServiceDelegateAndroid::Register}, - {"OfflinePageBridge", - offline_pages::android::RegisterOfflinePageBridge}, + {"OfflinePageBridge", offline_pages::android::RegisterOfflinePageBridge}, {"OmniboxPrerender", RegisterOmniboxPrerender}, {"OmniboxUrlEmphasizer", OmniboxUrlEmphasizer::RegisterOmniboxUrlEmphasizer}, diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index f0a1c647d729c1..4702e6eb810a61 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -603,6 +603,7 @@ '../components/components.gyp:precache_java', '../components/components.gyp:safe_json_java', '../components/components.gyp:service_tab_launcher_java', + '../components/components.gyp:signin_core_browser_java', '../components/components.gyp:variations_java', '../components/components.gyp:web_contents_delegate_android_java', '../content/content.gyp:content_java', diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 5694f4bc45695b..5c9e947b0858b5 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -1554,6 +1554,7 @@ 'dependencies': [ 'components_unittests', 'components.gyp:invalidation_java', + 'components.gyp:signin_core_browser_java', ], 'variables': { 'test_suite_name': 'components_unittests', diff --git a/components/signin.gypi b/components/signin.gypi index 6af3989a641c4a..be67e197f22ee4 100644 --- a/components/signin.gypi +++ b/components/signin.gypi @@ -59,8 +59,14 @@ 'signin/core/browser/account_reconcilor.h', 'signin/core/browser/account_tracker_service.cc', 'signin/core/browser/account_tracker_service.h', + 'signin/core/browser/android/component_jni_registrar.cc', + 'signin/core/browser/android/component_jni_registrar.h', 'signin/core/browser/child_account_info_fetcher.cc', 'signin/core/browser/child_account_info_fetcher.h', + 'signin/core/browser/child_account_info_fetcher_android.cc', + 'signin/core/browser/child_account_info_fetcher_android.h', + 'signin/core/browser/child_account_info_fetcher_impl.cc', + 'signin/core/browser/child_account_info_fetcher_impl.h', 'signin/core/browser/device_activity_fetcher.cc', 'signin/core/browser/device_activity_fetcher.h', 'signin/core/browser/gaia_cookie_manager_service.cc', @@ -97,6 +103,15 @@ 'signin/core/browser/webdata/token_web_data.h', ], 'conditions': [ + ['OS=="android"', { + 'dependencies': [ + 'signin_core_browser_jni_headers', + ], + 'sources!': [ + 'signin/core/browser/child_account_info_fetcher_impl.cc', + 'signin/core/browser/child_account_info_fetcher_impl.h', + ], + }], ['chromeos==1', { 'sources!': [ 'signin/core/browser/signin_manager.cc', @@ -131,6 +146,35 @@ }, ], 'conditions': [ + ['OS == "android"', { + 'targets': [ + { + # GN version: //components/signin/core/browser/android:java + 'target_name': 'signin_core_browser_java', + 'type': 'none', + 'dependencies': [ + '../base/base.gyp:base', + '../sync/sync.gyp:sync_java', + ], + 'variables': { + 'java_in_dir': 'signin/core/browser/android/java', + }, + 'includes': [ '../build/java.gypi' ], + }, + { + # GN version: //components/signin/core/browser/android:jni_headers + 'target_name': 'signin_core_browser_jni_headers', + 'type': 'none', + 'sources': [ + 'signin/core/browser/android/java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java', + ], + 'variables': { + 'jni_gen_package': 'components/signin', + }, + 'includes': [ '../build/jni_generator.gypi' ], + }, + ], + }], ['OS == "ios"', { # GN version: //components/signin/core/browser:ios 'targets': [ diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn index 8b1c92dfc90d50..c9c82ead86295a 100644 --- a/components/signin/core/browser/BUILD.gn +++ b/components/signin/core/browser/BUILD.gn @@ -14,8 +14,14 @@ static_library("browser") { "account_reconcilor.h", "account_tracker_service.cc", "account_tracker_service.h", + "android/component_jni_registrar.cc", + "android/component_jni_registrar.h", "child_account_info_fetcher.cc", "child_account_info_fetcher.h", + "child_account_info_fetcher_android.cc", + "child_account_info_fetcher_android.h", + "child_account_info_fetcher_impl.cc", + "child_account_info_fetcher_impl.h", "device_activity_fetcher.cc", "device_activity_fetcher.h", "gaia_cookie_manager_service.cc", @@ -73,6 +79,14 @@ static_library("browser") { if (is_chromeos) { sources -= [ "signin_manager.cc" ] } + + if (is_android) { + sources -= [ + "child_account_info_fetcher_impl.cc", + "child_account_info_fetcher_impl.h", + ] + deps += [ "android:jni_headers" ] + } } static_library("test_support") { diff --git a/components/signin/core/browser/DEPS b/components/signin/core/browser/DEPS index 80cef76eddc4b2..8486a6ba4be181 100644 --- a/components/signin/core/browser/DEPS +++ b/components/signin/core/browser/DEPS @@ -7,4 +7,5 @@ specific_include_rules = { include_rules = [ "+components/invalidation/public", "+google/cacheinvalidation", + "+jni", ] diff --git a/components/signin/core/browser/account_fetcher_service.cc b/components/signin/core/browser/account_fetcher_service.cc index 0ebae73f6ba288..5e3efd5240aeeb 100644 --- a/components/signin/core/browser/account_fetcher_service.cc +++ b/components/signin/core/browser/account_fetcher_service.cc @@ -185,9 +185,9 @@ void AccountFetcherService::StartFetchingChildInfo( if (!AccountSupportsUserInfo(account_id)) return; child_request_account_id_ = account_id; - child_info_request_.reset(new ChildAccountInfoFetcher( - token_service_, signin_client_->GetURLRequestContext(), this, - invalidation_service_, child_request_account_id_)); + child_info_request_.reset(ChildAccountInfoFetcher::CreateFrom( + child_request_account_id_, this, token_service_, + signin_client_->GetURLRequestContext(), invalidation_service_)); } void AccountFetcherService::ResetChildInfo() { @@ -267,7 +267,8 @@ void AccountFetcherService::OnUserInfoFetchSuccess( void AccountFetcherService::SetIsChildAccount(const std::string& account_id, bool is_child_account) { - account_tracker_service_->SetIsChildAccount(account_id, is_child_account); + if (child_request_account_id_ == account_id) + account_tracker_service_->SetIsChildAccount(account_id, is_child_account); } void AccountFetcherService::OnUserInfoFetchFailure( @@ -283,8 +284,8 @@ void AccountFetcherService::OnRefreshTokenAvailable( // (such as fetching the signin token "handle" in order to look for password // changes) once everything is initialized and the refresh token is present. signin_client_->DoFinalInit(); - UpdateChildInfo(); RefreshAccountInfo(account_id, true); + UpdateChildInfo(); } void AccountFetcherService::OnRefreshTokenRevoked( diff --git a/components/signin/core/browser/account_fetcher_service.h b/components/signin/core/browser/account_fetcher_service.h index 40b9a093bd8e7c..43ec20d7d7da31 100644 --- a/components/signin/core/browser/account_fetcher_service.h +++ b/components/signin/core/browser/account_fetcher_service.h @@ -59,7 +59,8 @@ class AccountFetcherService : public KeyedService, private: friend class AccountInfoFetcher; - friend class ChildAccountInfoFetcher; + friend class ChildAccountInfoFetcherImpl; + friend class ChildAccountInfoFetcherAndroid; void RefreshAllAccountInfo(bool only_fetch_if_invalid); void RefreshAllAccountsAndScheduleNext(); diff --git a/components/signin/core/browser/android/BUILD.gn b/components/signin/core/browser/android/BUILD.gn new file mode 100644 index 00000000000000..d130fdc3d6ac39 --- /dev/null +++ b/components/signin/core/browser/android/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2015 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. + +import("//build/config/android/rules.gni") + +# GYP version: components/signin.gypi:signin_core_browser_jni_headers +generate_jni("jni_headers") { + sources = [ + "java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java", + ] + jni_package = "components/signin" +} + +# GYP version: components/signin.gypi:signin_core_browser_java +android_library("java") { + deps = [ + "//base:base_java", + "//sync/android:sync_java", + ] + + DEPRECATED_java_in_dir = "java/src" +} diff --git a/components/signin/core/browser/android/component_jni_registrar.cc b/components/signin/core/browser/android/component_jni_registrar.cc new file mode 100644 index 00000000000000..2600b92dc61276 --- /dev/null +++ b/components/signin/core/browser/android/component_jni_registrar.cc @@ -0,0 +1,25 @@ +// Copyright 2015 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/android/component_jni_registrar.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_registrar.h" +#include "base/basictypes.h" +#include "components/signin/core/browser/child_account_info_fetcher_android.h" + +namespace signin { +namespace android { + +static base::android::RegistrationMethod kSigninRegisteredMethods[] = { + {"ChildAccountInfoFetcher", ChildAccountInfoFetcherAndroid::Register}, +}; + +bool RegisterSigninJni(JNIEnv* env) { + return base::android::RegisterNativeMethods( + env, kSigninRegisteredMethods, arraysize(kSigninRegisteredMethods)); +} + +} // namespace android +} // namespace signin diff --git a/components/signin/core/browser/android/component_jni_registrar.h b/components/signin/core/browser/android/component_jni_registrar.h new file mode 100644 index 00000000000000..442853fe076064 --- /dev/null +++ b/components/signin/core/browser/android/component_jni_registrar.h @@ -0,0 +1,18 @@ +// Copyright 2015 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_ANDROID_COMPONENT_JNI_REGISTRAR_H_ +#define COMPONENTS_SIGNIN_CORE_BROWSER_ANDROID_COMPONENT_JNI_REGISTRAR_H_ + +#include + +namespace signin { +namespace android { + +bool RegisterSigninJni(JNIEnv* env); + +} // namespace android +} // namespace signin + +#endif // COMPONENTS_SIGNIN_CORE_BROWSER_ANDROID_COMPONENT_JNI_REGISTRAR_H_ diff --git a/components/signin/core/browser/android/java/DEPS b/components/signin/core/browser/android/java/DEPS new file mode 100644 index 00000000000000..a7565d5e70a8e8 --- /dev/null +++ b/components/signin/core/browser/android/java/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+sync/android/java/src/org/chromium/sync/signin", +] diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java new file mode 100644 index 00000000000000..34f8a56da29048 --- /dev/null +++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/ChildAccountInfoFetcher.java @@ -0,0 +1,67 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.components.signin; + +import android.accounts.Account; +import android.accounts.AccountManagerCallback; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.Context; + +import org.chromium.base.ApplicationStatus; +import org.chromium.base.CalledByNative; +import org.chromium.base.Log; +import org.chromium.sync.signin.AccountManagerHelper; + +import java.io.IOException; + +/** + * ChildAccountInfoFetcher for the Android platform. + * Checks whether an account is a child account from the AccountManager. + */ +public final class ChildAccountInfoFetcher { + private static final String TAG = "cr.signin"; + + private ChildAccountInfoFetcher() { + // For static use only. + } + + @CalledByNative + private static void fetch(final long nativeAccountFetcherService, final String accountId) { + Context app = ApplicationStatus.getApplicationContext(); + assert app != null; + AccountManagerHelper helper = AccountManagerHelper.get(app); + Account[] accounts = helper.getGoogleAccounts(); + Account candidate_account = null; + for (Account account : accounts) { + if (account.name.equals(accountId)) { + candidate_account = account; + break; + } + } + if (candidate_account == null) { + nativeSetIsChildAccount(nativeAccountFetcherService, accountId, false); + return; + } + helper.checkChildAccount(candidate_account, new AccountManagerCallback() { + @Override + public void run(AccountManagerFuture future) { + assert future.isDone(); + try { + boolean isChildAccount = future.getResult(); + nativeSetIsChildAccount(nativeAccountFetcherService, accountId, isChildAccount); + } catch (AuthenticatorException | IOException e) { + Log.e(TAG, "Error while fetching child account info: ", e); + } catch (OperationCanceledException e) { + Log.e(TAG, "Child account info fetch was cancelled. This should not happen."); + } + } + }); + } + + private static native void nativeSetIsChildAccount( + long ptrAccountFetcherService, final String accountId, boolean isChildAccount); +} diff --git a/components/signin/core/browser/child_account_info_fetcher.cc b/components/signin/core/browser/child_account_info_fetcher.cc index a4ecb8572afe97..3ee32037c030b2 100644 --- a/components/signin/core/browser/child_account_info_fetcher.cc +++ b/components/signin/core/browser/child_account_info_fetcher.cc @@ -4,169 +4,31 @@ #include "components/signin/core/browser/child_account_info_fetcher.h" -#include "base/strings/string_split.h" -#include "base/trace_event/trace_event.h" -#include "base/values.h" -#include "components/invalidation/public/invalidation_service.h" -#include "components/invalidation/public/object_id_invalidation_map.h" -#include "components/signin/core/browser/account_fetcher_service.h" -#include "components/signin/core/browser/signin_client.h" -#include "google/cacheinvalidation/types.pb.h" -#include "google_apis/gaia/gaia_auth_fetcher.h" -#include "google_apis/gaia/gaia_constants.h" +#include "build/build_config.h" -namespace { +#if defined(OS_ANDROID) +#include "components/signin/core/browser/child_account_info_fetcher_android.h" +#else +#include "components/signin/core/browser/child_account_info_fetcher_impl.h" +#endif -const char kFetcherId[] = "child_account_info_fetcher"; - -// Exponential backoff policy on service flag fetching failure. -const net::BackoffEntry::Policy kBackoffPolicy = { - 0, // Number of initial errors to ignore without backoff. - 2000, // Initial delay for backoff in ms. - 2, // Factor to multiply waiting time by. - 0.2, // Fuzzing percentage. 20% will spread requests randomly between - // 80-100% of the calculated time. - 1000 * 60 * 60* 4, // Maximum time to delay requests by (4 hours). - -1, // Don't discard entry even if unused. - false, // Don't use the initial delay unless the last request was an error. -}; - -// The invalidation object ID used for child account graduation event. -// The syntax is: -// 'U' -> This is a user specific invalidation. -// 'CA' -> Namespace used for all ChildAccount invalidations. -// 'GRAD' -> Indicates the actual event i.e. child account graduation. -const char kChildAccountGraduationId[] = "UCAGRAD"; - -} // namespace - -ChildAccountInfoFetcher::ChildAccountInfoFetcher( +// static +ChildAccountInfoFetcher* ChildAccountInfoFetcher::CreateFrom( + const std::string& account_id, + AccountFetcherService* fetcher_service, OAuth2TokenService* token_service, net::URLRequestContextGetter* request_context_getter, - AccountFetcherService* fetcher_service, - invalidation::InvalidationService* invalidation_service, - const std::string& account_id) - : OAuth2TokenService::Consumer(kFetcherId), - token_service_(token_service), - request_context_getter_(request_context_getter), - fetcher_service_(fetcher_service), - invalidation_service_(invalidation_service), - account_id_(account_id), - backoff_(&kBackoffPolicy), - fetch_in_progress_(false) { - TRACE_EVENT_ASYNC_BEGIN1("AccountFetcherService", kFetcherId, this, - "account_id", account_id); - // Invalidation service may not be available in tests. - if (invalidation_service_) { - invalidation_service_->RegisterInvalidationHandler(this); - syncer::ObjectIdSet ids; - ids.insert(invalidation::ObjectId( - ipc::invalidation::ObjectSource::CHROME_COMPONENTS, - kChildAccountGraduationId)); - bool insert_success = - invalidation_service_->UpdateRegisteredInvalidationIds(this, ids); - DCHECK(insert_success); - } - FetchIfNotInProgress(); + invalidation::InvalidationService* invalidation_service) { +#if defined(OS_ANDROID) + ChildAccountInfoFetcherAndroid::StartFetchingChildAccountInfo(fetcher_service, + account_id); + return nullptr; +#else + return new ChildAccountInfoFetcherImpl(account_id, fetcher_service, + token_service, request_context_getter, + invalidation_service); +#endif } ChildAccountInfoFetcher::~ChildAccountInfoFetcher() { - TRACE_EVENT_ASYNC_END0("AccountFetcherService", kFetcherId, this); - if (invalidation_service_) - invalidation_service_->UnregisterInvalidationHandler(this); -} - -void ChildAccountInfoFetcher::FetchIfNotInProgress() { - DCHECK(thread_checker_.CalledOnValidThread()); - if (fetch_in_progress_) - return; - fetch_in_progress_ = true; - OAuth2TokenService::ScopeSet scopes; - scopes.insert(GaiaConstants::kOAuth1LoginScope); - login_token_request_.reset( - token_service_->StartRequest(account_id_, scopes, this).release()); -} - -void ChildAccountInfoFetcher::OnGetTokenSuccess( - const OAuth2TokenService::Request* request, - const std::string& access_token, - const base::Time& expiration_time) { - TRACE_EVENT_ASYNC_STEP_PAST0("AccountFetcherService", kFetcherId, this, - "OnGetTokenSuccess"); - DCHECK_EQ(request, login_token_request_.get()); - - gaia_auth_fetcher_.reset( - fetcher_service_->signin_client_->CreateGaiaAuthFetcher( - this, GaiaConstants::kChromeSource, request_context_getter_)); - gaia_auth_fetcher_->StartOAuthLogin(access_token, - GaiaConstants::kGaiaService); -} - -void ChildAccountInfoFetcher::OnGetTokenFailure( - const OAuth2TokenService::Request* request, - const GoogleServiceAuthError& error) { - HandleFailure(); -} - -void ChildAccountInfoFetcher::OnClientLoginSuccess( - const ClientLoginResult& result) { - gaia_auth_fetcher_->StartGetUserInfo(result.lsid); -} - -void ChildAccountInfoFetcher::OnClientLoginFailure( - const GoogleServiceAuthError& error) { - HandleFailure(); -} - -void ChildAccountInfoFetcher::OnGetUserInfoSuccess(const UserInfoMap& data) { - UserInfoMap::const_iterator services_iter = data.find("allServices"); - if (services_iter != data.end()) { - std::vector service_flags; - base::SplitString(services_iter->second, ',', &service_flags); - bool is_child_account = - std::find(service_flags.begin(), service_flags.end(), - AccountTrackerService::kChildAccountServiceFlag) != - service_flags.end(); - if (!is_child_account && invalidation_service_) { - // Don't bother listening for invalidations as a non-child account can't - // become a child account. - bool insert_success = - invalidation_service_->UpdateRegisteredInvalidationIds( - this, syncer::ObjectIdSet()); - DCHECK(insert_success); - invalidation_service_->UnregisterInvalidationHandler(this); - invalidation_service_ = nullptr; - } - fetcher_service_->SetIsChildAccount(account_id_, is_child_account); - } else { - DLOG(ERROR) << "ChildAccountInfoFetcher::OnGetUserInfoSuccess: " - << "GetUserInfo response didn't include allServices field."; - } - fetch_in_progress_ = false; -} - -void ChildAccountInfoFetcher::OnGetUserInfoFailure( - const GoogleServiceAuthError& error) { - HandleFailure(); -} - -void ChildAccountInfoFetcher::HandleFailure() { - fetch_in_progress_ = false; - backoff_.InformOfRequest(false); - timer_.Start(FROM_HERE, backoff_.GetTimeUntilRelease(), this, - &ChildAccountInfoFetcher::FetchIfNotInProgress); -} - -void ChildAccountInfoFetcher::OnInvalidatorStateChange( - syncer::InvalidatorState state) { -} - -void ChildAccountInfoFetcher::OnIncomingInvalidation( - const syncer::ObjectIdInvalidationMap& invalidation_map) { - FetchIfNotInProgress(); - invalidation_map.AcknowledgeAll(); -} - -std::string ChildAccountInfoFetcher::GetOwnerName() const { - return std::string(kFetcherId); } diff --git a/components/signin/core/browser/child_account_info_fetcher.h b/components/signin/core/browser/child_account_info_fetcher.h index 8b019f31610fec..90dfaed2a9cefe 100644 --- a/components/signin/core/browser/child_account_info_fetcher.h +++ b/components/signin/core/browser/child_account_info_fetcher.h @@ -5,74 +5,33 @@ #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_H_ #define COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_H_ -#include "base/threading/thread_checker.h" -#include "base/timer/timer.h" -#include "components/invalidation/public/invalidation_handler.h" -#include "google_apis/gaia/gaia_auth_consumer.h" -#include "google_apis/gaia/oauth2_token_service.h" -#include "net/base/backoff_entry.h" +#include + +#if defined(OS_ANDROID) +#include +#endif -namespace net { -class URLRequestContextGetter; -} namespace invalidation { class InvalidationService; } +namespace net { +class URLRequestContextGetter; +} class AccountFetcherService; -class GaiaAuthFetcher; +class OAuth2TokenService; -class ChildAccountInfoFetcher : public OAuth2TokenService::Consumer, - public GaiaAuthConsumer, - public syncer::InvalidationHandler { +class ChildAccountInfoFetcher { public: - ChildAccountInfoFetcher( + // Caller takes ownership of the fetcher and keeps it alive in order to + // receive updates except on Android where the return value is a nullptr + // and there are no updates due to a stale OS cache. + static ChildAccountInfoFetcher* CreateFrom( + const std::string& account_id, + AccountFetcherService* fetcher_service, OAuth2TokenService* token_service, net::URLRequestContextGetter* request_context_getter, - AccountFetcherService* fetcher_service, - invalidation::InvalidationService* invalidation_service, - const std::string& account_id); - ~ChildAccountInfoFetcher() override; - - private: - void FetchIfNotInProgress(); - void HandleFailure(); - - // OAuth2TokenService::Consumer: - void OnGetTokenSuccess(const OAuth2TokenService::Request* request, - const std::string& access_token, - const base::Time& expiration_time) override; - void OnGetTokenFailure(const OAuth2TokenService::Request* request, - const GoogleServiceAuthError& error) override; - - // GaiaAuthConsumer: - void OnClientLoginSuccess(const ClientLoginResult& result) override; - void OnClientLoginFailure(const GoogleServiceAuthError& error) override; - void OnGetUserInfoSuccess(const UserInfoMap& data) override; - void OnGetUserInfoFailure(const GoogleServiceAuthError& error) override; - - // syncer::InvalidationHandler: - void OnInvalidatorStateChange(syncer::InvalidatorState state) override; - void OnIncomingInvalidation( - const syncer::ObjectIdInvalidationMap& invalidation_map) override; - std::string GetOwnerName() const override; - - OAuth2TokenService* token_service_; - net::URLRequestContextGetter* request_context_getter_; - AccountFetcherService* fetcher_service_; - invalidation::InvalidationService* invalidation_service_; - const std::string account_id_; - - // If fetching fails, retry with exponential backoff. - base::OneShotTimer timer_; - net::BackoffEntry backoff_; - - scoped_ptr login_token_request_; - scoped_ptr gaia_auth_fetcher_; - - bool fetch_in_progress_; - base::ThreadChecker thread_checker_; - - DISALLOW_COPY_AND_ASSIGN(ChildAccountInfoFetcher); + invalidation::InvalidationService* invalidation_service); + virtual ~ChildAccountInfoFetcher(); }; #endif // COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_H_ diff --git a/components/signin/core/browser/child_account_info_fetcher_android.cc b/components/signin/core/browser/child_account_info_fetcher_android.cc new file mode 100644 index 00000000000000..8b30e12c6c0a23 --- /dev/null +++ b/components/signin/core/browser/child_account_info_fetcher_android.cc @@ -0,0 +1,45 @@ +// Copyright 2015 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/child_account_info_fetcher_android.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "components/signin/core/browser/account_fetcher_service.h" +#include "jni/ChildAccountInfoFetcher_jni.h" + +// static +void ChildAccountInfoFetcherAndroid::StartFetchingChildAccountInfo( + AccountFetcherService* service, + const std::string& account_id) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_ChildAccountInfoFetcher_fetch( + env, reinterpret_cast(service), + base::android::ConvertUTF8ToJavaString(env, account_id).obj()); +} + +// static +void ChildAccountInfoFetcherAndroid::SetIsChildAccount( + AccountFetcherService* service, + std::string account_id, + bool is_child_account) { + service->SetIsChildAccount(account_id, is_child_account); +} + +// static +bool ChildAccountInfoFetcherAndroid::Register(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +void SetIsChildAccount(JNIEnv* env, + jclass caller, + jlong native_service, + jstring j_account_id, + jboolean is_child_account) { + AccountFetcherService* service = + reinterpret_cast(native_service); + ChildAccountInfoFetcherAndroid::SetIsChildAccount( + service, base::android::ConvertJavaStringToUTF8(env, j_account_id), + is_child_account); +} diff --git a/components/signin/core/browser/child_account_info_fetcher_android.h b/components/signin/core/browser/child_account_info_fetcher_android.h new file mode 100644 index 00000000000000..371a7b18266706 --- /dev/null +++ b/components/signin/core/browser/child_account_info_fetcher_android.h @@ -0,0 +1,28 @@ +// Copyright 2015 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_CHILD_ACCOUNT_INFO_FETCHER_ANDROID_H_ +#define COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_ANDROID_H_ + +#include +#include + +#include "base/macros.h" + +class AccountFetcherService; + +class ChildAccountInfoFetcherAndroid { + public: + static void StartFetchingChildAccountInfo(AccountFetcherService* service, + const std::string& account_id); + static void SetIsChildAccount(AccountFetcherService* service, + std::string account_id, + bool is_child_account); + // Register JNI methods. + static bool Register(JNIEnv* env); + + DISALLOW_IMPLICIT_CONSTRUCTORS(ChildAccountInfoFetcherAndroid); +}; + +#endif // COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_ANDROID_H_ diff --git a/components/signin/core/browser/child_account_info_fetcher_impl.cc b/components/signin/core/browser/child_account_info_fetcher_impl.cc new file mode 100644 index 00000000000000..d897ca0c4a21be --- /dev/null +++ b/components/signin/core/browser/child_account_info_fetcher_impl.cc @@ -0,0 +1,173 @@ +// Copyright 2015 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/child_account_info_fetcher_impl.h" + +#include "base/strings/string_split.h" +#include "base/trace_event/trace_event.h" +#include "base/values.h" +#include "components/invalidation/public/invalidation_service.h" +#include "components/invalidation/public/object_id_invalidation_map.h" +#include "components/signin/core/browser/account_fetcher_service.h" +#include "components/signin/core/browser/signin_client.h" +#include "google/cacheinvalidation/types.pb.h" +#include "google_apis/gaia/gaia_auth_fetcher.h" +#include "google_apis/gaia/gaia_constants.h" + +namespace { + +const char kFetcherId[] = "ChildAccountInfoFetcherImpl"; + +// Exponential backoff policy on service flag fetching failure. +const net::BackoffEntry::Policy kBackoffPolicy = { + 0, // Number of initial errors to ignore without backoff. + 2000, // Initial delay for backoff in ms. + 2, // Factor to multiply waiting time by. + 0.2, // Fuzzing percentage. 20% will spread requests randomly between + // 80-100% of the calculated time. + 1000 * 60 * 60* 4, // Maximum time to delay requests by (4 hours). + -1, // Don't discard entry even if unused. + false, // Don't use the initial delay unless the last request was an error. +}; + +// The invalidation object ID used for child account graduation event. +// The syntax is: +// 'U' -> This is a user specific invalidation. +// 'CA' -> Namespace used for all ChildAccount invalidations. +// 'GRAD' -> Indicates the actual event i.e. child account graduation. +const char kChildAccountGraduationId[] = "UCAGRAD"; + +} // namespace + +ChildAccountInfoFetcherImpl::ChildAccountInfoFetcherImpl( + const std::string& account_id, + AccountFetcherService* fetcher_service, + OAuth2TokenService* token_service, + net::URLRequestContextGetter* request_context_getter, + invalidation::InvalidationService* invalidation_service) + : OAuth2TokenService::Consumer(kFetcherId), + token_service_(token_service), + request_context_getter_(request_context_getter), + fetcher_service_(fetcher_service), + invalidation_service_(invalidation_service), + account_id_(account_id), + backoff_(&kBackoffPolicy), + fetch_in_progress_(false) { + TRACE_EVENT_ASYNC_BEGIN1("AccountFetcherService", kFetcherId, this, + "account_id", account_id); + // Invalidation service may not be available in tests. + if (invalidation_service_) { + invalidation_service_->RegisterInvalidationHandler(this); + syncer::ObjectIdSet ids; + ids.insert(invalidation::ObjectId( + ipc::invalidation::ObjectSource::CHROME_COMPONENTS, + kChildAccountGraduationId)); + bool insert_success = + invalidation_service_->UpdateRegisteredInvalidationIds(this, ids); + DCHECK(insert_success); + } + FetchIfNotInProgress(); +} + +ChildAccountInfoFetcherImpl::~ChildAccountInfoFetcherImpl() { + TRACE_EVENT_ASYNC_END0("AccountFetcherService", kFetcherId, this); + if (invalidation_service_) + invalidation_service_->UnregisterInvalidationHandler(this); +} + +void ChildAccountInfoFetcherImpl::FetchIfNotInProgress() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (fetch_in_progress_) + return; + fetch_in_progress_ = true; + OAuth2TokenService::ScopeSet scopes; + scopes.insert(GaiaConstants::kOAuth1LoginScope); + login_token_request_.reset( + token_service_->StartRequest(account_id_, scopes, this).release()); +} + +void ChildAccountInfoFetcherImpl::OnGetTokenSuccess( + const OAuth2TokenService::Request* request, + const std::string& access_token, + const base::Time& expiration_time) { + TRACE_EVENT_ASYNC_STEP_PAST0("AccountFetcherService", kFetcherId, this, + "OnGetTokenSuccess"); + DCHECK_EQ(request, login_token_request_.get()); + + gaia_auth_fetcher_.reset( + fetcher_service_->signin_client_->CreateGaiaAuthFetcher( + this, GaiaConstants::kChromeSource, request_context_getter_)); + gaia_auth_fetcher_->StartOAuthLogin(access_token, + GaiaConstants::kGaiaService); +} + +void ChildAccountInfoFetcherImpl::OnGetTokenFailure( + const OAuth2TokenService::Request* request, + const GoogleServiceAuthError& error) { + HandleFailure(); +} + +void ChildAccountInfoFetcherImpl::OnClientLoginSuccess( + const ClientLoginResult& result) { + gaia_auth_fetcher_->StartGetUserInfo(result.lsid); +} + +void ChildAccountInfoFetcherImpl::OnClientLoginFailure( + const GoogleServiceAuthError& error) { + HandleFailure(); +} + +void ChildAccountInfoFetcherImpl::OnGetUserInfoSuccess( + const UserInfoMap& data) { + UserInfoMap::const_iterator services_iter = data.find("allServices"); + if (services_iter != data.end()) { + std::vector service_flags; + base::SplitString(services_iter->second, ',', &service_flags); + bool is_child_account = + std::find(service_flags.begin(), service_flags.end(), + AccountTrackerService::kChildAccountServiceFlag) != + service_flags.end(); + if (!is_child_account && invalidation_service_) { + // Don't bother listening for invalidations as a non-child account can't + // become a child account. + bool insert_success = + invalidation_service_->UpdateRegisteredInvalidationIds( + this, syncer::ObjectIdSet()); + DCHECK(insert_success); + invalidation_service_->UnregisterInvalidationHandler(this); + invalidation_service_ = nullptr; + } + fetcher_service_->SetIsChildAccount(account_id_, is_child_account); + } else { + DLOG(ERROR) << "ChildAccountInfoFetcherImpl::OnGetUserInfoSuccess: " + << "GetUserInfo response didn't include allServices field."; + } + fetch_in_progress_ = false; +} + +void ChildAccountInfoFetcherImpl::OnGetUserInfoFailure( + const GoogleServiceAuthError& error) { + HandleFailure(); +} + +void ChildAccountInfoFetcherImpl::HandleFailure() { + fetch_in_progress_ = false; + backoff_.InformOfRequest(false); + timer_.Start(FROM_HERE, backoff_.GetTimeUntilRelease(), this, + &ChildAccountInfoFetcherImpl::FetchIfNotInProgress); +} + +void ChildAccountInfoFetcherImpl::OnInvalidatorStateChange( + syncer::InvalidatorState state) { +} + +void ChildAccountInfoFetcherImpl::OnIncomingInvalidation( + const syncer::ObjectIdInvalidationMap& invalidation_map) { + FetchIfNotInProgress(); + invalidation_map.AcknowledgeAll(); +} + +std::string ChildAccountInfoFetcherImpl::GetOwnerName() const { + return std::string(kFetcherId); +} diff --git a/components/signin/core/browser/child_account_info_fetcher_impl.h b/components/signin/core/browser/child_account_info_fetcher_impl.h new file mode 100644 index 00000000000000..25cfeb2eb74a57 --- /dev/null +++ b/components/signin/core/browser/child_account_info_fetcher_impl.h @@ -0,0 +1,73 @@ +// Copyright 2015 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_CHILD_ACCOUNT_INFO_FETCHER_IMPL_H_ +#define COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_IMPL_H_ + +#include "base/threading/thread_checker.h" +#include "base/timer/timer.h" +#include "components/invalidation/public/invalidation_handler.h" +#include "components/signin/core/browser/child_account_info_fetcher.h" +#include "google_apis/gaia/gaia_auth_consumer.h" +#include "google_apis/gaia/oauth2_token_service.h" +#include "net/base/backoff_entry.h" + +class GaiaAuthFetcher; + +class ChildAccountInfoFetcherImpl : public ChildAccountInfoFetcher, + public OAuth2TokenService::Consumer, + public GaiaAuthConsumer, + public syncer::InvalidationHandler { + public: + ChildAccountInfoFetcherImpl( + const std::string& account_id, + AccountFetcherService* fetcher_service, + OAuth2TokenService* token_service, + net::URLRequestContextGetter* request_context_getter, + invalidation::InvalidationService* invalidation_service); + ~ChildAccountInfoFetcherImpl() override; + + private: + void FetchIfNotInProgress(); + void HandleFailure(); + + // OAuth2TokenService::Consumer: + void OnGetTokenSuccess(const OAuth2TokenService::Request* request, + const std::string& access_token, + const base::Time& expiration_time) override; + void OnGetTokenFailure(const OAuth2TokenService::Request* request, + const GoogleServiceAuthError& error) override; + + // GaiaAuthConsumer: + void OnClientLoginSuccess(const ClientLoginResult& result) override; + void OnClientLoginFailure(const GoogleServiceAuthError& error) override; + void OnGetUserInfoSuccess(const UserInfoMap& data) override; + void OnGetUserInfoFailure(const GoogleServiceAuthError& error) override; + + // syncer::InvalidationHandler: + void OnInvalidatorStateChange(syncer::InvalidatorState state) override; + void OnIncomingInvalidation( + const syncer::ObjectIdInvalidationMap& invalidation_map) override; + std::string GetOwnerName() const override; + + OAuth2TokenService* token_service_; + net::URLRequestContextGetter* request_context_getter_; + AccountFetcherService* fetcher_service_; + invalidation::InvalidationService* invalidation_service_; + const std::string account_id_; + + // If fetching fails, retry with exponential backoff. + base::OneShotTimer timer_; + net::BackoffEntry backoff_; + + scoped_ptr login_token_request_; + scoped_ptr gaia_auth_fetcher_; + + bool fetch_in_progress_; + base::ThreadChecker thread_checker_; + + DISALLOW_COPY_AND_ASSIGN(ChildAccountInfoFetcherImpl); +}; + +#endif // COMPONENTS_SIGNIN_CORE_BROWSER_CHILD_ACCOUNT_INFO_FETCHER_IMPL_H_ diff --git a/components/test/DEPS b/components/test/DEPS index d36f58a4e2cd2a..640fa0a5f2902e 100644 --- a/components/test/DEPS +++ b/components/test/DEPS @@ -4,6 +4,7 @@ include_rules = [ "+components/invalidation/impl/android/component_jni_registrar.h", "+components/policy/core/browser/android/component_jni_registrar.h", "+components/safe_json/android/component_jni_registrar.h", + "+components/signin/core/browser/android/component_jni_registrar.h", "+content/public/android/java/src/org/chromium/content/browser", "+content/public/app/content_jni_onload.h", "+content/public/app/content_main.h", diff --git a/components/test/run_all_unittests.cc b/components/test/run_all_unittests.cc index 4c299246821240..572eb6f7b517b5 100644 --- a/components/test/run_all_unittests.cc +++ b/components/test/run_all_unittests.cc @@ -25,6 +25,7 @@ #include "components/invalidation/impl/android/component_jni_registrar.h" #include "components/policy/core/browser/android/component_jni_registrar.h" #include "components/safe_json/android/component_jni_registrar.h" +#include "components/signin/core/browser/android/component_jni_registrar.h" #include "ui/base/android/ui_base_jni_registrar.h" #include "ui/gfx/android/gfx_jni_registrar.h" #endif @@ -55,6 +56,7 @@ class ComponentsTestSuite : public base::TestSuite { ASSERT_TRUE(invalidation::android::RegisterInvalidationJni(env)); ASSERT_TRUE(policy::android::RegisterPolicy(env)); ASSERT_TRUE(safe_json::android::RegisterSafeJsonJni(env)); + ASSERT_TRUE(signin::android::RegisterSigninJni(env)); #endif ui::RegisterPathProvider();