Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / signin / android_profile_oauth2_token_service.cc
blob9f8fac9134527bb9654f4c0193ea59904953a5db
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/signin/android_profile_oauth2_token_service.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "chrome/browser/profiles/profile_android.h"
13 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
14 #include "chrome/browser/sync/profile_sync_service_android.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "google_apis/gaia/gaia_auth_util.h"
17 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
18 #include "jni/OAuth2TokenService_jni.h"
20 using base::android::AttachCurrentThread;
21 using base::android::ConvertJavaStringToUTF8;
22 using base::android::ConvertUTF8ToJavaString;
23 using base::android::ScopedJavaLocalRef;
24 using content::BrowserThread;
26 namespace {
28 // Callback from FetchOAuth2TokenWithUsername().
29 // Arguments:
30 // - the error, or NONE if the token fetch was successful.
31 // - the OAuth2 access token.
32 // - the expiry time of the token (may be null, indicating that the expiry
33 // time is unknown.
34 typedef base::Callback<void(
35 const GoogleServiceAuthError&, const std::string&, const base::Time&)>
36 FetchOAuth2TokenCallback;
38 class AndroidAccessTokenFetcher : public OAuth2AccessTokenFetcher {
39 public:
40 AndroidAccessTokenFetcher(OAuth2AccessTokenConsumer* consumer,
41 const std::string& account_id);
42 virtual ~AndroidAccessTokenFetcher();
44 // Overrides from OAuth2AccessTokenFetcher:
45 virtual void Start(const std::string& client_id,
46 const std::string& client_secret,
47 const std::vector<std::string>& scopes) override;
48 virtual void CancelRequest() override;
50 // Handles an access token response.
51 void OnAccessTokenResponse(const GoogleServiceAuthError& error,
52 const std::string& access_token,
53 const base::Time& expiration_time);
55 private:
56 std::string CombineScopes(const std::vector<std::string>& scopes);
58 base::WeakPtrFactory<AndroidAccessTokenFetcher> weak_factory_;
59 std::string account_id_;
60 bool request_was_cancelled_;
62 DISALLOW_COPY_AND_ASSIGN(AndroidAccessTokenFetcher);
65 AndroidAccessTokenFetcher::AndroidAccessTokenFetcher(
66 OAuth2AccessTokenConsumer* consumer,
67 const std::string& account_id)
68 : OAuth2AccessTokenFetcher(consumer),
69 weak_factory_(this),
70 account_id_(account_id),
71 request_was_cancelled_(false) {
74 AndroidAccessTokenFetcher::~AndroidAccessTokenFetcher() {}
76 void AndroidAccessTokenFetcher::Start(const std::string& client_id,
77 const std::string& client_secret,
78 const std::vector<std::string>& scopes) {
79 JNIEnv* env = AttachCurrentThread();
80 std::string scope = CombineScopes(scopes);
81 ScopedJavaLocalRef<jstring> j_username =
82 ConvertUTF8ToJavaString(env, account_id_);
83 ScopedJavaLocalRef<jstring> j_scope =
84 ConvertUTF8ToJavaString(env, scope);
85 scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
86 new FetchOAuth2TokenCallback(
87 base::Bind(&AndroidAccessTokenFetcher::OnAccessTokenResponse,
88 weak_factory_.GetWeakPtr())));
90 // Call into Java to get a new token.
91 Java_OAuth2TokenService_getOAuth2AuthToken(
92 env, base::android::GetApplicationContext(),
93 j_username.obj(),
94 j_scope.obj(),
95 reinterpret_cast<intptr_t>(heap_callback.release()));
98 void AndroidAccessTokenFetcher::CancelRequest() {
99 request_was_cancelled_ = true;
102 void AndroidAccessTokenFetcher::OnAccessTokenResponse(
103 const GoogleServiceAuthError& error,
104 const std::string& access_token,
105 const base::Time& expiration_time) {
106 if (request_was_cancelled_) {
107 // Ignore the callback if the request was cancelled.
108 return;
110 if (error.state() == GoogleServiceAuthError::NONE) {
111 FireOnGetTokenSuccess(access_token, expiration_time);
112 } else {
113 FireOnGetTokenFailure(error);
117 // static
118 std::string AndroidAccessTokenFetcher::CombineScopes(
119 const std::vector<std::string>& scopes) {
120 // The Android AccountManager supports multiple scopes separated by a space:
121 // https://code.google.com/p/google-api-java-client/wiki/OAuth2#Android
122 std::string scope;
123 for (std::vector<std::string>::const_iterator it = scopes.begin();
124 it != scopes.end(); ++it) {
125 if (!scope.empty())
126 scope += " ";
127 scope += *it;
129 return scope;
132 } // namespace
134 bool AndroidProfileOAuth2TokenService::is_testing_profile_ = false;
136 AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService() {
137 VLOG(1) << "AndroidProfileOAuth2TokenService::ctor";
138 JNIEnv* env = AttachCurrentThread();
139 base::android::ScopedJavaLocalRef<jobject> local_java_ref =
140 Java_OAuth2TokenService_create(env, reinterpret_cast<intptr_t>(this));
141 java_ref_.Reset(env, local_java_ref.obj());
144 AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {}
146 // static
147 jobject AndroidProfileOAuth2TokenService::GetForProfile(
148 JNIEnv* env, jclass clazz, jobject j_profile_android) {
149 Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile_android);
150 AndroidProfileOAuth2TokenService* service =
151 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(profile);
152 return service->java_ref_.obj();
155 static jobject GetForProfile(JNIEnv* env,
156 jclass clazz,
157 jobject j_profile_android) {
158 return AndroidProfileOAuth2TokenService::GetForProfile(
159 env, clazz, j_profile_android);
162 void AndroidProfileOAuth2TokenService::Initialize(SigninClient* client) {
163 VLOG(1) << "AndroidProfileOAuth2TokenService::Initialize";
164 ProfileOAuth2TokenService::Initialize(client);
166 if (!is_testing_profile_) {
167 Java_OAuth2TokenService_validateAccounts(
168 AttachCurrentThread(), java_ref_.obj(),
169 base::android::GetApplicationContext(), JNI_TRUE);
173 bool AndroidProfileOAuth2TokenService::RefreshTokenIsAvailable(
174 const std::string& account_id) const {
175 JNIEnv* env = AttachCurrentThread();
176 ScopedJavaLocalRef<jstring> j_account_id =
177 ConvertUTF8ToJavaString(env, account_id);
178 jboolean refresh_token_is_available =
179 Java_OAuth2TokenService_hasOAuth2RefreshToken(
180 env, base::android::GetApplicationContext(),
181 j_account_id.obj());
182 return refresh_token_is_available == JNI_TRUE;
185 void AndroidProfileOAuth2TokenService::UpdateAuthError(
186 const std::string& account_id,
187 const GoogleServiceAuthError& error) {
188 // TODO(rogerta): do we need to update anything, or does the system handle it?
191 std::vector<std::string> AndroidProfileOAuth2TokenService::GetAccounts() {
192 std::vector<std::string> accounts;
193 JNIEnv* env = AttachCurrentThread();
194 ScopedJavaLocalRef<jobjectArray> j_accounts =
195 Java_OAuth2TokenService_getAccounts(
196 env, base::android::GetApplicationContext());
197 // TODO(fgorski): We may decide to filter out some of the accounts.
198 base::android::AppendJavaStringArrayToStringVector(env,
199 j_accounts.obj(),
200 &accounts);
201 return accounts;
204 std::vector<std::string> AndroidProfileOAuth2TokenService::GetSystemAccounts() {
205 std::vector<std::string> accounts;
206 JNIEnv* env = AttachCurrentThread();
207 ScopedJavaLocalRef<jobjectArray> j_accounts =
208 Java_OAuth2TokenService_getSystemAccounts(
209 env, base::android::GetApplicationContext());
210 base::android::AppendJavaStringArrayToStringVector(env,
211 j_accounts.obj(),
212 &accounts);
213 return accounts;
216 OAuth2AccessTokenFetcher*
217 AndroidProfileOAuth2TokenService::CreateAccessTokenFetcher(
218 const std::string& account_id,
219 net::URLRequestContextGetter* getter,
220 OAuth2AccessTokenConsumer* consumer) {
221 ValidateAccountId(account_id);
222 return new AndroidAccessTokenFetcher(consumer, account_id);
225 void AndroidProfileOAuth2TokenService::InvalidateOAuth2Token(
226 const std::string& account_id,
227 const std::string& client_id,
228 const ScopeSet& scopes,
229 const std::string& access_token) {
230 ValidateAccountId(account_id);
231 OAuth2TokenService::InvalidateOAuth2Token(account_id,
232 client_id,
233 scopes,
234 access_token);
236 JNIEnv* env = AttachCurrentThread();
237 ScopedJavaLocalRef<jstring> j_access_token =
238 ConvertUTF8ToJavaString(env, access_token);
239 Java_OAuth2TokenService_invalidateOAuth2AuthToken(
240 env, base::android::GetApplicationContext(),
241 j_access_token.obj());
244 void AndroidProfileOAuth2TokenService::ValidateAccounts(
245 JNIEnv* env,
246 jobject obj,
247 jstring j_current_acc,
248 jboolean j_force_notifications) {
249 VLOG(1) << "AndroidProfileOAuth2TokenService::ValidateAccounts from java";
250 std::string signed_in_account = ConvertJavaStringToUTF8(env, j_current_acc);
251 if (!signed_in_account.empty())
252 signed_in_account = gaia::CanonicalizeEmail(signed_in_account);
253 ValidateAccounts(signed_in_account, j_force_notifications != JNI_FALSE);
256 void AndroidProfileOAuth2TokenService::ValidateAccounts(
257 const std::string& signed_in_account,
258 bool force_notifications) {
259 std::vector<std::string> prev_ids = GetAccounts();
260 std::vector<std::string> curr_ids = GetSystemAccounts();
261 std::vector<std::string> refreshed_ids;
262 std::vector<std::string> revoked_ids;
264 // Canonicalize system accounts. |prev_ids| is already done.
265 for (size_t i = 0; i < curr_ids.size(); ++i)
266 curr_ids[i] = gaia::CanonicalizeEmail(curr_ids[i]);
267 for (size_t i = 0; i < prev_ids.size(); ++i)
268 ValidateAccountId(prev_ids[i]);
270 VLOG(1) << "AndroidProfileOAuth2TokenService::ValidateAccounts:"
271 << " sigined_in_account=" << signed_in_account
272 << " prev_ids=" << prev_ids.size()
273 << " curr_ids=" << curr_ids.size()
274 << " force=" << (force_notifications ? "true" : "false");
276 if (!ValidateAccounts(signed_in_account, prev_ids, curr_ids, refreshed_ids,
277 revoked_ids, force_notifications)) {
278 curr_ids.clear();
281 ScopedBacthChange batch(this);
283 JNIEnv* env = AttachCurrentThread();
284 ScopedJavaLocalRef<jobjectArray> java_accounts(
285 base::android::ToJavaArrayOfStrings(env, curr_ids));
286 Java_OAuth2TokenService_saveStoredAccounts(
287 env, base::android::GetApplicationContext(), java_accounts.obj());
289 for (std::vector<std::string>::iterator it = refreshed_ids.begin();
290 it != refreshed_ids.end(); it++) {
291 FireRefreshTokenAvailable(*it);
294 for (std::vector<std::string>::iterator it = revoked_ids.begin();
295 it != revoked_ids.end(); it++) {
296 FireRefreshTokenRevoked(*it);
300 bool AndroidProfileOAuth2TokenService::ValidateAccounts(
301 const std::string& signed_in_account,
302 const std::vector<std::string>& prev_account_ids,
303 const std::vector<std::string>& curr_account_ids,
304 std::vector<std::string>& refreshed_ids,
305 std::vector<std::string>& revoked_ids,
306 bool force_notifications) {
307 if (std::find(curr_account_ids.begin(),
308 curr_account_ids.end(),
309 signed_in_account) != curr_account_ids.end()) {
310 // Test to see if an account is removed from the Android AccountManager.
311 // If so, invoke FireRefreshTokenRevoked to notify the reconcilor.
312 for (std::vector<std::string>::const_iterator it = prev_account_ids.begin();
313 it != prev_account_ids.end(); it++) {
314 if (*it == signed_in_account)
315 continue;
317 if (std::find(curr_account_ids.begin(),
318 curr_account_ids.end(),
319 *it) == curr_account_ids.end()) {
320 VLOG(1) << "AndroidProfileOAuth2TokenService::ValidateAccounts:"
321 << "revoked=" << *it;
322 revoked_ids.push_back(*it);
326 if (force_notifications ||
327 std::find(prev_account_ids.begin(), prev_account_ids.end(),
328 signed_in_account) == prev_account_ids.end()) {
329 // Always fire the primary signed in account first.
330 VLOG(1) << "AndroidProfileOAuth2TokenService::ValidateAccounts:"
331 << "refreshed=" << signed_in_account;
332 refreshed_ids.push_back(signed_in_account);
335 for (std::vector<std::string>::const_iterator it = curr_account_ids.begin();
336 it != curr_account_ids.end(); it++) {
337 if (*it != signed_in_account) {
338 if (force_notifications ||
339 std::find(prev_account_ids.begin(),
340 prev_account_ids.end(),
341 *it) == prev_account_ids.end()) {
342 VLOG(1) << "AndroidProfileOAuth2TokenService::ValidateAccounts:"
343 << "refreshed=" << *it;
344 refreshed_ids.push_back(*it);
348 return true;
349 } else {
350 // Currently signed in account does not any longer exist among accounts on
351 // system together with all other accounts.
352 if (std::find(prev_account_ids.begin(), prev_account_ids.end(),
353 signed_in_account) != prev_account_ids.end()) {
354 VLOG(1) << "AndroidProfileOAuth2TokenService::ValidateAccounts:"
355 << "revoked=" << signed_in_account;
356 revoked_ids.push_back(signed_in_account);
358 for (std::vector<std::string>::const_iterator it = prev_account_ids.begin();
359 it != prev_account_ids.end(); it++) {
360 if (*it == signed_in_account)
361 continue;
362 VLOG(1) << "AndroidProfileOAuth2TokenService::ValidateAccounts:"
363 << "revoked=" << *it;
364 revoked_ids.push_back(*it);
366 return false;
370 void AndroidProfileOAuth2TokenService::FireRefreshTokenAvailableFromJava(
371 JNIEnv* env,
372 jobject obj,
373 const jstring account_name) {
374 std::string account_id = ConvertJavaStringToUTF8(env, account_name);
375 AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable(account_id);
378 void AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable(
379 const std::string& account_id) {
380 VLOG(1) << "AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable id="
381 << account_id;
383 // Notify native observers.
384 OAuth2TokenService::FireRefreshTokenAvailable(account_id);
385 // Notify Java observers.
386 JNIEnv* env = AttachCurrentThread();
387 ScopedJavaLocalRef<jstring> account_name =
388 ConvertUTF8ToJavaString(env, account_id);
389 Java_OAuth2TokenService_notifyRefreshTokenAvailable(
390 env, java_ref_.obj(), account_name.obj());
393 void AndroidProfileOAuth2TokenService::FireRefreshTokenRevokedFromJava(
394 JNIEnv* env,
395 jobject obj,
396 const jstring account_name) {
397 std::string account_id = ConvertJavaStringToUTF8(env, account_name);
398 AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked(account_id);
401 void AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked(
402 const std::string& account_id) {
403 VLOG(1) << "AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked id="
404 << account_id;
406 // Notify native observers.
407 OAuth2TokenService::FireRefreshTokenRevoked(account_id);
408 // Notify Java observers.
409 JNIEnv* env = AttachCurrentThread();
410 ScopedJavaLocalRef<jstring> account_name =
411 ConvertUTF8ToJavaString(env, account_id);
412 Java_OAuth2TokenService_notifyRefreshTokenRevoked(
413 env, java_ref_.obj(), account_name.obj());
416 void AndroidProfileOAuth2TokenService::FireRefreshTokensLoadedFromJava(
417 JNIEnv* env,
418 jobject obj) {
419 AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded();
422 void AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded() {
423 VLOG(1) << "AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded";
424 // Notify native observers.
425 OAuth2TokenService::FireRefreshTokensLoaded();
426 // Notify Java observers.
427 JNIEnv* env = AttachCurrentThread();
428 Java_OAuth2TokenService_notifyRefreshTokensLoaded(
429 env, java_ref_.obj());
432 void AndroidProfileOAuth2TokenService::RevokeAllCredentials() {
433 VLOG(1) << "AndroidProfileOAuth2TokenService::RevokeAllCredentials";
434 ScopedBacthChange batch(this);
435 std::vector<std::string> accounts = GetAccounts();
436 for (std::vector<std::string>::iterator it = accounts.begin();
437 it != accounts.end(); it++) {
438 FireRefreshTokenRevoked(*it);
441 // Clear everything on the Java side as well.
442 std::vector<std::string> empty;
443 JNIEnv* env = AttachCurrentThread();
444 ScopedJavaLocalRef<jobjectArray> java_accounts(
445 base::android::ToJavaArrayOfStrings(env, empty));
446 Java_OAuth2TokenService_saveStoredAccounts(
447 env, base::android::GetApplicationContext(), java_accounts.obj());
450 // Called from Java when fetching of an OAuth2 token is finished. The
451 // |authToken| param is only valid when |result| is true.
452 void OAuth2TokenFetched(
453 JNIEnv* env,
454 jclass clazz,
455 jstring authToken,
456 jboolean result,
457 jlong nativeCallback) {
458 std::string token = ConvertJavaStringToUTF8(env, authToken);
459 scoped_ptr<FetchOAuth2TokenCallback> heap_callback(
460 reinterpret_cast<FetchOAuth2TokenCallback*>(nativeCallback));
461 // Android does not provide enough information to know if the credentials are
462 // wrong, so assume any error is transient by using CONNECTION_FAILED.
463 GoogleServiceAuthError err(result ?
464 GoogleServiceAuthError::NONE :
465 GoogleServiceAuthError::CONNECTION_FAILED);
466 heap_callback->Run(err, token, base::Time());
469 // static
470 bool AndroidProfileOAuth2TokenService::Register(JNIEnv* env) {
471 return RegisterNativesImpl(env);