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 "jni/OAuth2TokenService_jni.h"
18 using base::android::AttachCurrentThread
;
19 using base::android::ConvertJavaStringToUTF8
;
20 using base::android::ConvertUTF8ToJavaString
;
21 using base::android::ScopedJavaLocalRef
;
22 using content::BrowserThread
;
26 std::string
CombineScopes(const OAuth2TokenService::ScopeSet
& scopes
) {
27 // The Android AccountManager supports multiple scopes separated by a space:
28 // https://code.google.com/p/google-api-java-client/wiki/OAuth2#Android
30 for (OAuth2TokenService::ScopeSet::const_iterator it
= scopes
.begin();
31 it
!= scopes
.end(); ++it
) {
39 // Callback from FetchOAuth2TokenWithUsername().
41 // - the error, or NONE if the token fetch was successful.
42 // - the OAuth2 access token.
43 // - the expiry time of the token (may be null, indicating that the expiry
45 typedef base::Callback
<void(
46 const GoogleServiceAuthError
&, const std::string
&, const base::Time
&)>
47 FetchOAuth2TokenCallback
;
51 AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService() {
52 JNIEnv
* env
= AttachCurrentThread();
53 base::android::ScopedJavaLocalRef
<jobject
> local_java_ref
=
54 Java_OAuth2TokenService_create(env
, reinterpret_cast<intptr_t>(this));
55 java_ref_
.Reset(env
, local_java_ref
.obj());
58 AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {}
61 jobject
AndroidProfileOAuth2TokenService::GetForProfile(
62 JNIEnv
* env
, jclass clazz
, jobject j_profile_android
) {
63 Profile
* profile
= ProfileAndroid::FromProfileAndroid(j_profile_android
);
64 AndroidProfileOAuth2TokenService
* service
=
65 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(profile
);
66 return service
->java_ref_
.obj();
69 static jobject
GetForProfile(JNIEnv
* env
,
71 jobject j_profile_android
) {
72 return AndroidProfileOAuth2TokenService::GetForProfile(
73 env
, clazz
, j_profile_android
);
76 bool AndroidProfileOAuth2TokenService::RefreshTokenIsAvailable(
77 const std::string
& account_id
) const {
78 JNIEnv
* env
= AttachCurrentThread();
79 ScopedJavaLocalRef
<jstring
> j_account_id
=
80 ConvertUTF8ToJavaString(env
, account_id
);
81 jboolean refresh_token_is_available
=
82 Java_OAuth2TokenService_hasOAuth2RefreshToken(
83 env
, base::android::GetApplicationContext(),
85 return refresh_token_is_available
!= JNI_FALSE
;
88 std::vector
<std::string
> AndroidProfileOAuth2TokenService::GetAccounts() {
89 std::vector
<std::string
> accounts
;
90 JNIEnv
* env
= AttachCurrentThread();
91 ScopedJavaLocalRef
<jobjectArray
> j_accounts
=
92 Java_OAuth2TokenService_getAccounts(
93 env
, base::android::GetApplicationContext());
94 // TODO(fgorski): We may decide to filter out some of the accounts.
95 base::android::AppendJavaStringArrayToStringVector(env
,
101 std::vector
<std::string
> AndroidProfileOAuth2TokenService::GetSystemAccounts() {
102 std::vector
<std::string
> accounts
;
103 JNIEnv
* env
= AttachCurrentThread();
104 ScopedJavaLocalRef
<jobjectArray
> j_accounts
=
105 Java_OAuth2TokenService_getSystemAccounts(
106 env
, base::android::GetApplicationContext());
107 base::android::AppendJavaStringArrayToStringVector(env
,
113 void AndroidProfileOAuth2TokenService::FetchOAuth2Token(
114 RequestImpl
* request
,
115 const std::string
& account_id
,
116 net::URLRequestContextGetter
* getter
,
117 const std::string
& client_id
,
118 const std::string
& client_secret
,
119 const OAuth2TokenService::ScopeSet
& scopes
) {
120 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
121 DCHECK(!account_id
.empty());
123 JNIEnv
* env
= AttachCurrentThread();
124 std::string scope
= CombineScopes(scopes
);
125 ScopedJavaLocalRef
<jstring
> j_username
=
126 ConvertUTF8ToJavaString(env
, account_id
);
127 ScopedJavaLocalRef
<jstring
> j_scope
=
128 ConvertUTF8ToJavaString(env
, scope
);
130 // Allocate a copy of the request WeakPtr on the heap, because the object
131 // needs to be passed through JNI as an int.
132 // It will be passed back to OAuth2TokenFetched(), where it will be freed.
133 scoped_ptr
<FetchOAuth2TokenCallback
> heap_callback(
134 new FetchOAuth2TokenCallback(base::Bind(&RequestImpl::InformConsumer
,
135 request
->AsWeakPtr())));
137 // Call into Java to get a new token.
138 Java_OAuth2TokenService_getOAuth2AuthToken(
139 env
, base::android::GetApplicationContext(),
142 reinterpret_cast<intptr_t>(heap_callback
.release()));
145 OAuth2AccessTokenFetcher
*
146 AndroidProfileOAuth2TokenService::CreateAccessTokenFetcher(
147 const std::string
& account_id
,
148 net::URLRequestContextGetter
* getter
,
149 OAuth2AccessTokenConsumer
* consumer
) {
154 void AndroidProfileOAuth2TokenService::InvalidateOAuth2Token(
155 const std::string
& account_id
,
156 const std::string
& client_id
,
157 const ScopeSet
& scopes
,
158 const std::string
& access_token
) {
159 OAuth2TokenService::InvalidateOAuth2Token(account_id
,
164 JNIEnv
* env
= AttachCurrentThread();
165 ScopedJavaLocalRef
<jstring
> j_access_token
=
166 ConvertUTF8ToJavaString(env
, access_token
);
167 Java_OAuth2TokenService_invalidateOAuth2AuthToken(
168 env
, base::android::GetApplicationContext(),
169 j_access_token
.obj());
172 void AndroidProfileOAuth2TokenService::ValidateAccounts(
175 jstring j_current_acc
) {
176 std::string signed_in_account
= ConvertJavaStringToUTF8(env
, j_current_acc
);
177 ValidateAccounts(signed_in_account
);
180 void AndroidProfileOAuth2TokenService::ValidateAccounts(
181 const std::string
& signed_in_account
) {
182 std::vector
<std::string
> prev_ids
= GetAccounts();
183 std::vector
<std::string
> curr_ids
= GetSystemAccounts();
185 if (!ValidateAccounts(signed_in_account
, prev_ids
, curr_ids
)) {
189 JNIEnv
* env
= AttachCurrentThread();
190 ScopedJavaLocalRef
<jobjectArray
> java_accounts(
191 base::android::ToJavaArrayOfStrings(env
, curr_ids
));
192 Java_OAuth2TokenService_saveStoredAccounts(
193 env
, base::android::GetApplicationContext(), java_accounts
.obj());
196 bool AndroidProfileOAuth2TokenService::ValidateAccounts(
197 const std::string
& signed_in_account
,
198 const std::vector
<std::string
>& prev_account_ids
,
199 const std::vector
<std::string
>& curr_account_ids
) {
200 if (std::find(curr_account_ids
.begin(),
201 curr_account_ids
.end(),
202 signed_in_account
) != curr_account_ids
.end()) {
203 // Test to see if an account is removed from the Android AccountManager.
204 // If so, invoke FireRefreshTokenRevoked to notify the reconcilor.
205 for (std::vector
<std::string
>::const_iterator it
= prev_account_ids
.begin();
206 it
!= prev_account_ids
.end(); it
++) {
207 if (*it
== signed_in_account
)
210 if (std::find(curr_account_ids
.begin(),
211 curr_account_ids
.end(),
212 *it
) == curr_account_ids
.end()) {
213 FireRefreshTokenRevoked(*it
);
217 // Always fire the primary signed in account first.
218 FireRefreshTokenAvailable(signed_in_account
);
220 for (std::vector
<std::string
>::const_iterator it
= curr_account_ids
.begin();
221 it
!= curr_account_ids
.end(); it
++) {
222 if (*it
!= signed_in_account
) {
223 FireRefreshTokenAvailable(*it
);
228 // Currently signed in account does not any longer exist among accounts on
229 // system together with all other accounts.
230 if (!signed_in_account
.empty()) {
231 FireRefreshTokenRevoked(signed_in_account
);
233 for (std::vector
<std::string
>::const_iterator it
= prev_account_ids
.begin();
234 it
!= prev_account_ids
.end(); it
++) {
235 if (*it
== signed_in_account
)
237 FireRefreshTokenRevoked(*it
);
243 void AndroidProfileOAuth2TokenService::FireRefreshTokenAvailableFromJava(
246 const jstring account_name
) {
247 std::string account_id
= ConvertJavaStringToUTF8(env
, account_name
);
248 AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable(account_id
);
251 void AndroidProfileOAuth2TokenService::FireRefreshTokenAvailable(
252 const std::string
& account_id
) {
253 // Notify native observers.
254 OAuth2TokenService::FireRefreshTokenAvailable(account_id
);
255 // Notify Java observers.
256 JNIEnv
* env
= AttachCurrentThread();
257 ScopedJavaLocalRef
<jstring
> account_name
=
258 ConvertUTF8ToJavaString(env
, account_id
);
259 Java_OAuth2TokenService_notifyRefreshTokenAvailable(
260 env
, java_ref_
.obj(), account_name
.obj());
263 void AndroidProfileOAuth2TokenService::FireRefreshTokenRevokedFromJava(
266 const jstring account_name
) {
267 std::string account_id
= ConvertJavaStringToUTF8(env
, account_name
);
268 AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked(account_id
);
271 void AndroidProfileOAuth2TokenService::FireRefreshTokenRevoked(
272 const std::string
& account_id
) {
273 // Notify native observers.
274 OAuth2TokenService::FireRefreshTokenRevoked(account_id
);
275 // Notify Java observers.
276 JNIEnv
* env
= AttachCurrentThread();
277 ScopedJavaLocalRef
<jstring
> account_name
=
278 ConvertUTF8ToJavaString(env
, account_id
);
279 Java_OAuth2TokenService_notifyRefreshTokenRevoked(
280 env
, java_ref_
.obj(), account_name
.obj());
283 void AndroidProfileOAuth2TokenService::FireRefreshTokensLoadedFromJava(
286 AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded();
289 void AndroidProfileOAuth2TokenService::FireRefreshTokensLoaded() {
290 // Notify native observers.
291 OAuth2TokenService::FireRefreshTokensLoaded();
292 // Notify Java observers.
293 JNIEnv
* env
= AttachCurrentThread();
294 Java_OAuth2TokenService_notifyRefreshTokensLoaded(
295 env
, java_ref_
.obj());
298 void AndroidProfileOAuth2TokenService::RevokeAllCredentials() {
299 std::vector
<std::string
> accounts
= GetAccounts();
300 for (std::vector
<std::string
>::iterator it
= accounts
.begin();
301 it
!= accounts
.end(); it
++) {
302 FireRefreshTokenRevoked(*it
);
306 // Called from Java when fetching of an OAuth2 token is finished. The
307 // |authToken| param is only valid when |result| is true.
308 void OAuth2TokenFetched(JNIEnv
* env
, jclass clazz
,
311 jlong nativeCallback
) {
312 std::string token
= ConvertJavaStringToUTF8(env
, authToken
);
313 scoped_ptr
<FetchOAuth2TokenCallback
> heap_callback(
314 reinterpret_cast<FetchOAuth2TokenCallback
*>(nativeCallback
));
315 // Android does not provide enough information to know if the credentials are
316 // wrong, so assume any error is transient by using CONNECTION_FAILED.
317 GoogleServiceAuthError
err(result
?
318 GoogleServiceAuthError::NONE
:
319 GoogleServiceAuthError::CONNECTION_FAILED
);
320 heap_callback
->Run(err
, token
, base::Time());
324 bool AndroidProfileOAuth2TokenService::Register(JNIEnv
* env
) {
325 return RegisterNativesImpl(env
);